지직전기

[데이터베이스] 9주차 교육 정리 본문

STUDY/DataBase

[데이터베이스] 9주차 교육 정리

MSH103 2024. 1. 29. 17:24

목차

  • 데이터 입출력
    • 입력스트림과 출력스트림
    • OutputStream
    • InputStream
    • Writer(문자 출력 스트림)
    • Reader(문자 입력 스트림)
    • 보조 스트림
  • 자바 네트워크
    • 네트워크 기초 용어 정리
    • TCP
    • UDP
    • JSON
  • 쓰레드
    • Executor과 ExecutorService
    • ExecutorService의 종류
    • 주요 인터페이스
  • 이상현상
  • 함수종속성
  • 정규화

입력스트림과 출력 스트림

  • 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 나가면 출력스트림
  • 프로그램이 다른 프로그램과 데이터를 교환하려면 양쪽 모두 입력 스트림과 출력 스트림이 필요
  • 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
  • 문자 스트림 : 문자만 입출력할 때 사용
  • JAVA는 데이터 입출력과 관련된 라이브러리를 java.io 패키지에서 제공

 

OutputStream

  • OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스
  • 모든 바이트 출력 스트림 클래스는 이 OutputStram 클래스를 상속받아서 만들어짐
  • OutputStram 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메소드가 정의됨

OutputStream스트림 메소드

1바이트 출력

write(int b) 메소드 : 매개값 int(4byte)에서 끝 1byte만 출력. 매개변수는 int 타입

바이트 배열 출력

write(byte[] b) 메소드 : 매개값으로 주어진 배열의 모든 바이트를 출력

배열의 일부분을 출력하려면 write(byte[] b, int off, int len) 메소드를 사용

 

InputStream

  • InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스
  • 모든 바이트 입력 스트림은 inputStram 클래스를 상속받아 만들어짐
  • InpuStream 클래스에는 바이트 입력 스트림이 기본적으로 가져야 할 메소드가 정의됨

InputStream 메소드

1바이트 입력

read() 메소드 : 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴. 리턴된 4byte 중 끝 1byte에만 데이터가 들어있음

더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴.
읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있음.

바이트 배열 읽기

read(byte[] b) 메소드 : 입력 스트림으로부터 주어진 배열이 길이만큼 바이트를 읽고 배

열에 저장한 다음 읽은 바이트 수를 리턴

read(byte[] b)도 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴
읽을 수 있는 마지막 바이트까지 반복해서 읽을수 있음

데이터 입출력 예제

// 입력 예시 (c:/temp/test2.text 파일에 10, 20, 30, 40, 50이라는 데이터값을 입력)
public class WriterEx01 {
    public static void main(String[] args) {
        try {
            OutputStream os = new FileOutputStream("C:/Temp/test2.text");
            byte[] a = {10, 20, 30, 40, 50};

            os.write(a, 1, a.length - 1);
            os.flush();
            os.close();

        } catch (IOException io) {
          io.printStackTrace();
        }
    }
}

//출력 예시
public class ReadEx01 {
    public static void main(String[] args) {
        try {
        InputStream is = new FileInputStream("C:/Temp/test2.text");
            while (true) {
                int b = is.read();
                if (b == -1) {  // EoF : 파일의 끝(-1을 리턴)
                    break;
                }
                System.out.println(b + " ");
            }
            is.close();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException io){
            io.printStackTrace();
            }

        }
    }

// 파일 복사
public class FileCopyEx01 {
    public static void main(String[] args) {
        String originFileName = "C:/Temp/imageEx.jpg";
        String targetFileName = "C:/Temp/imageEx2.jpg";
        try {

            InputStream is = new FileInputStream(originFileName);
            OutputStream os = new FileOutputStream(targetFileName);
/*            byte[] data = new byte[30919];    --> 사진파일 복사
//            while (true) {
//                int num = is.read(data);
//                if (num == -1) {
//                    System.out.println("copyEnd!");
//                    break;
//                }
//                os.write(data, 0, num);
            } */
            is.transferTo(os);  //Java 9버전부터 추가된 기능(위에 주석문을 대체)
            os.flush();
            is.close();
            os.close();
        }catch (IOException io){
            io.printStackTrace();
        }
    }
}

 

 

Writer(문자 출력 스트림)

  • Writer는 문자 출력 스트림의 최상위 클래스로, 추상클래스이다. 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속.
  • Writer 클래스에는 모든 문자 출력 스트림이 기본적으로 가져야 할 메소드가 정의됨

Writer 클래스 메소드

  • Reader(문자 입력 스트림)
  • Reader는 문자 입력 스트림의 최상위 클래스로, 추상 클래스
  • 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어짐
  • Reader 클래스에는 문자 입력 스트림이 기본적으로 가져야 할 메소드가 정의됨

 

보조 스트림

  • 다른 스트림과 연결되어 여러 편리한 기능을 제공해주는 스트림
  • 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결되어 사용
  • 입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출려겨 스트림을 제공
  • 보조 스트림 변수 = new 보조스트림(입출력스트림)
  • 보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있음
  • 보조 스트림2 변수 = new  보조 스트림2(보조 스트림1);

네트워크 기초 용어 정리

네트워크

  • 네트워크 : 여러 컴퓨터들을 통신 회선으로 연결한 것
  • LAN : 가정, 회사, 건물, 특정 영역에 존재하는 컴퓨터를 연결한 것
  • WAN : LAN을 연결한 것 = 인터넷
  • 서버와 클라이언트
  • 서버 : 서비스를 제공하는 프로그램
  • 클라이언트 : 서비스를 요청하는 프로그램
  • 먼저 클라이언트가 서비스를 요청하고, 서버는 처리 결과를 응답으로 제공

IP주소

  • IP주소 : 네트워크 어댑터(LAN 카드) 마다 할당되는 컴퓨터의 고유한 주소
  • ipconfig(윈도우) 명령어로 네트워크 어댑터에 어떤 ip 주소가 부여되어 있는지 확인
  • 프로그램은 DNS를 이용해서 컴퓨터의 IP 주소를 검색

Port 번호

  • 운영체제가 관리하는 서버 프로그램의 연결 번호. 서버 시작 시 특정 Port 번호에 바인딩

IP 주소 얻기

  • InetAddress(java.net)
  • 자바는 IP 주소를 java.net 패키지의 InetAddress로 표현
  • 로컬 컴퓨터의 InetAddress를 얻으려면 InetAddress.getLocalHost() 메소드를 호출
  • getByName() 메소드는 DNS에서 도메인  이름으로 등록된 단 하나의 IP 주소를 가져오고,
    getAllByName() 메소드는 등록된 모든 IP 주소를 배열로 가져옴
  • InetAddress 객체에서 IP 주소를 얻으려면 getHostAddress() 메소드 호출
String ip = InetAddress.getHostAddress();

 

TCP

  • TCP는 연결형 프로토콜로, 상대방이 연결된 상태에서 데이터를 주고 받는 전송용 프로토콜
  • 클라이언트가 연결 요청을 하고 서버가 연결을 수락하면 통신 회선이 고정되고, 데이터는 고정회선을 통해 전달. TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지않음(흐름제어, 순서제어)
  • ServerSocket은 클라이언트의 연결을 수락하는 서버 쪽 클래스이고, Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고 받을 때 사용되는 클래스

 

TCP 클라이언트

  • 클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP주소와 Port 번호를 제공
  • 로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP주소 대신 localhost 사용 가능
  • 도메인 이름을 사용하려면 DNS에서 IP주소를 검색하는 생성자 매개값으로 InetSocketAddress 제공
  • 기본 생성자로 Socket을 생성한 후 connect()메소드로 연결 요청 가능
socket = new Socket();
socket.connect(new InetSocketAddress("domainName", 50001);

 

입출력 스트림으로 데이터 주고 받기

  • 클라이언트가 연결 요청(connext())을 하고 서버가 연결 수락(accecpt())했다면, 양쪽의 Socket객체로부터 각각 InputStream과 OutputStream을 얻을 수 있다.
  • 상대방에게 데이터를 보낼 때에는 보낼 데이터를 byte[] 배열로 생성하고, 이것을 매개값으로해서 OutputStream의 write()메소드를 호출
  • 문자열을 좀 더 간편하게 보내고 싶다면 보조 스트림인 DataOutputStream을 연결해서 사용
  • 데이터를 받기 위해서는 받은 데이터를 저장할 byte[] 배열을 하나 생성하고, 이것을 매개값으로 해서 InputStream의 read()메소드를 호출
  • read() 메소드는 읽은 데이터를 byte[] 배열에 저장하고 읽은 바이트 수를 리턴
  • 문자열을 좀 더 간편하게 받고 싶다면 보조 스트림인 DataInputStream을 연결해서 사용
byte[] byte = new byte[1024];
InputStream is = socket.getInputStream();
int num = is.read(bytes);
String data = new String(bytes, 0, num, "UTF-8");

DataInputStream dis = new DataInputStream(socket.getInputStream());
String data = dis.readUTF();

 

UDP

  • 발신자가 일방적으로 수신자에게 데이터를 보내는 방식. TCP처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠름
  • 데이터 전달의 신뢰성보다 속도가 중요하다면 UDP를 사용하고, 데이터 전달의 신뢰성이 중요하다면 TCP를 사용
  • DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고 받는 데이터에 해당

UDP 클라이언트

  • 서버에 요청 내용을 보내고 그 결과를 받는 역할
  • UDP 클라이언트를 위한 DatagramSocket 객체는 기본 생성자로 생성. Port 번호는 자동 부여
  • 생성된 DatagramPacket을 매개값으로 해서 DatagramSocket의 send() 메소드를 호출하면 UDP 서버로 DatagramPacket이 전송
  • DatagramSocket을 닫으려면 close() 메소드를 호출

 

서버의 동시 요청 처리

  • 일반적으로 서버는 다수의 클라이언트와 통신. 서버는 클라이언트들로부터 동시에 요청을 받아서 처리하고 처리 결과를 개별 클라이언트로 보내줌
  • accept()와 receive()를 제외한 요청 처리 코드를 별도의 스레드에서 작업
  • 스레드를 처리할 때 클라이언트의 폭증으로 인한 서버의 과도한 스레드 생성을 방지하기 위해 스레드풀을 사용하는 것이 바람직

 

JSON

  • 네트워크로 전달하는 데이터 형식
  • 두 개 이상의 속성이 있으면 객체{}로 표기. 두 개 이상의 값이 있으면 배열[]로 표기

채팅 서버와 클라이언트 구현

  • TCP 네트워킹을 이용해서 채팅 서버와 클라이언트를 구현
  • 채팅서버 : ChatServer는 채팅 서버 실행 클래스로 클라이언트의 연결 요청을 수락하고 통신용 SocketClient를 생성하는 역할
  • 채팅 클라이언트 : 단일 클래스 ChatClient는 채팅 서버로 연결을 요청하고, 연결된 후에는 제일 먼저 대화명을 보내며 다음 서버와 메시지를 주고 받음

쓰레드란?

  • CPU에 작업 요청을 하는 실행 단위를 말합니다.
  • 프로그램을 실행하기 위해 운영체제는 프로세스를 생성하게 되는데 프로세스가 생성되면 CPU 스케줄러는 CPU에게 해야 하는일을 전달하고 CPU가 그 일을 하게되는데 이 때 CPU가 받는 일을 쓰레드라고 합니다.
  • 쉽게 비유하자면 오늘 내가 할일이 밥 먹기, 공부하기 등이라면 밥 먹기, 공부하기 같은 일은 프로세스에 해당이 되고 밥을 먹기위해 밥 짓기, 반찬 준비하기 등 식사 차리는 작업은 스레드에 해당됩니다. 또한, 밥 짓기와 반찬 준비를 동시에 하게되는 것을 멀티스레드라고 합니다.

 

Executor과 ExecutorService

  • ExecutorService는 병렬작업 시 여러개의 작업을 효율적으로 처리하기 위해 제공되는 JAVA의 라이브러리이다.
  • 통상적으로 작업을 분리하고 수행하는 작업을 손수 구현하고자 하면.. 각기 다른 Thread를 생성해서 작업을 처리하고, 처리가 완료되면 해당 Thread를 제거하는 작업을 진행해야 한다.
  • 이러한 일련의 작업을 이 클래스를 이용해서 쉽게 처리가 가능하다.
  • 흔히 말하는 ThreadPool을 구현하기가 매우 용이하므로, Java에서 쓰레드풀을 생성해서 사용하고자 하면 (손수 구축이 아닌.. 보장된 동작을 원한다면 이를 사용하길 적극 추천) 반드시 사용을 고려해봐야 할 유틸리티성 클래스이다.

ExecutorService의 종류

  • newFixedThreadPool(int) : 인자 갯수만큼 고정된 쓰레드풀을 생성한다.
  • newCachedThreadPool(): 필요할 때 필요한 만큼 쓰레드풀을 생성한다. 이미 생성된 쓰레드를 재활용 할 수 있기 때문에 성능상의 이점이 있을 수 있다.
  • newScheduledThreadPool(int) : 일정 시간 뒤에 실행되는 작업이나, 주기적으로 수행되는 쓰레드풀을 인자 갯수만큼 생성한다.
  • newSingleThreadExecutor() : 단일 쓰레드인 풀을 생성한다. 단일 쓰레드에서 동작해야 하는 작업을 처리할 때 사용한다.
  • newWorkStrealingPool(int parallelism) : 시스템에 가용 가능한 만큼 쓰레드를 활용하는 ExecutorService를 생성한다.

 

주요 인터페이스

Executors

  • execute(Runnable) : Executor 내 인터페이스 내 작업을 실행하는 메소드.
  • ExecutorService :  Executor를 상속 받은 인터페이스
  • shutdown() : 어떤 작업을 실행하고 나면 다음 작업이 들어올 때까지 계속 대기하기 때문에 프로세스를 끄기 위해 Shutdown을 해야한다. Graceful shutdown이라고도 하며 현재 진행 중인 작업은 끝까지 마치고 끝내는 것이다.
  • shutdownNow() : 프로세스가 작업을 처리할 때까지 기다리지 않고 즉시 종료한다.
  • submit(Callable | Runnable) : 작업을 실행하는 메소드. Executors를 상속받았기에 execute를 써도 되지만 submit를 쓰면 Future타입 리턴받아 GET메소드로 결과를 가져올 수 있다.
  • ScheduledExcutorService : ScheduledExecutorServiec는 ExecuterServie를 상속받은 인터페이스이다.
    • schedule(Runnable, long, TimeUnit) : 특정시간 이후에 딜레이를 시키는 동안 어떤 작업을 하거나, 주기적으로 어떤 작업을 실행하고 싶을 때 사용하는 함수형 인터페이스이다.
    • scheduleWithFixedDelay : 특정시간 이후 처음 작업을 실행 시킴. 작업이 완료되고 특정 시간이 지나면 작업을 실행시킴
    • scheduleAtFixedRate : 특정시간 이후 처음 작업을 실행시킴. 작업이 실행되고 특정시간마다 작업을 실행시킴

 

이상현상

  • 잘못된 설계로 테이블이 생성되면 데이터 조작 작업시 이상현상이 발생할 수 있다.
  • 이상현상은 데이터의 일관성을 손상시켜 데이터의 무결성을 깨뜨린다.
  • 이 문제를 해결하려면 속성 간의 함수 종속성을 분석하여 데이터 베이스 설계를 수행해야한다.

 

이상현상 종류

  1. 삽입 이상 : 테이블에 데이터를 삽입할 때 의도하지 않은 결과가 발생하는 현상
  2. 갱신 이상 : 데이터를 업데이트할 때 일부만 업데이트되어 데이터의 불일치가 발생하는 현상
  3. 삭제 이상 : 데이터를 삭제할 때 의도하지 않은 데이터의 손실이 발생하는 현상

 

함수종속성

  • 함수종속성은 데이터베이스에서 한 속성이 다른 속성에 종속되어 있는 관계를 나타냄
  • 하나의 속성의 값이 결정되면 다른 속성의 값도 결정되는 것을 말한다.(X → Y)

 

함수종속성의 종류

  1. 완전 함수 종속성 : 하나의 속성 그룹이 다른 속성 그룹에 대해 완전히 함수적으로 종속되어 있는 경우를 말함
  2. 부분 함수 종속성 : 어떤 속성 그룹이 다른 속성 그룹에 대해 부분적으로만 함수적으로 종속되어 있는 경우를 말함
  3. 이행적 함수 종속성 : 속성 그룹 간의 종속성이 체이닝 되어있는 경우.  ex) X→Y, Y→Z일때 X →Z이다

 

함수종속성의 특징

  1. 데이터 베이스의 설계 : 함수 종속성을 분석하여 정규화를 수행하여 데이터 중복과 이상 현상을 최소화 할 수 있다.
  2. 쿼리 최적화 : 함수 종속성을 이해하면 쿼리의 조인과 필터링 조건을 최적화하여 데이터베이스의 성능을 향상시킨다.

 

정규화

  • 정규화란 잘못 설계된 테이블을 수정하여 데이터의 일관성과 무결성을 회복하는 프로세스
  • (중복성과 종속성을 제거(최소화) 데이터베이스의 효율성과 유지보수의 구조를 개선하고
  • 데이터베이스의 성능 향상을 최적화하는데 의미가 있다.

 

주요 정규화 형식 제 1정규형 ~ 제 3정규형

  • 제1정규형 : 테이블이 각 송성 값은 반복그룹이 없는 원자값으로만 구성되도록 중복되는 송성이나 속성 그룹을 별도의 테이블로 분리한다.
  • 제2정규형 : 1NF를 만족하면서 부분 함수적 종속성을 제거해야 한다. 기본키 속성에 완전 함수적 종속성을 가짇록 테이블을 분할하거나 기본키를 변경하거나 속성간의 종속성을 조정.
  • 제3정규형 : 2NF를 만족하면서 이행 함수적 종속성을 제거해야한다. 테이블의 모든 비(Non-key)속성은 기본키에만 종속되어야 하고, 비-키 속성간에는 종속성이 존재하지 않아야 한다.
    만약 종속성이 존재한다면 테이블 분할해야 한다.
  • 반정규화(Denormalization) : 중복 데이터를 하나 이상의 테이블에 추가하는 데이터 베이스 최적화 기술 이를 통해 관계형 데이터베이스에서 비용이 많이 드는 조인의 수를 줄일 수 있다.
  • 반정규화는 정규화를 되돌린다거나 정규화 되지않음을 의미하는 것이 아니라, 정규화 후에 적용되는 최적화기업
    • 장점 : 더 적은 수의 테이블을 사용하면서 조인 개수를 줄일 수 있고, 이로 인해 검색 쿼리가 간단해지고 빠른 읽기 작업의 수행으로 검색성능이 좋아진다.
    • 단점 : 중복 저장으로 더 많은 스토리지가 요구된다. 도한 데이터 불일치가 발생할 수 있으며, 쓰기 작업에 추가적은 비용이 발생할 수 있다.