지직전기
[데이터베이스] 9주차 교육 정리 본문
목차
- 데이터 입출력
- 입력스트림과 출력스트림
- 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 : 특정시간 이후 처음 작업을 실행시킴. 작업이 실행되고 특정시간마다 작업을 실행시킴
이상현상
- 잘못된 설계로 테이블이 생성되면 데이터 조작 작업시 이상현상이 발생할 수 있다.
- 이상현상은 데이터의 일관성을 손상시켜 데이터의 무결성을 깨뜨린다.
- 이 문제를 해결하려면 속성 간의 함수 종속성을 분석하여 데이터 베이스 설계를 수행해야한다.
이상현상 종류
- 삽입 이상 : 테이블에 데이터를 삽입할 때 의도하지 않은 결과가 발생하는 현상
- 갱신 이상 : 데이터를 업데이트할 때 일부만 업데이트되어 데이터의 불일치가 발생하는 현상
- 삭제 이상 : 데이터를 삭제할 때 의도하지 않은 데이터의 손실이 발생하는 현상
함수종속성
- 함수종속성은 데이터베이스에서 한 속성이 다른 속성에 종속되어 있는 관계를 나타냄
- 하나의 속성의 값이 결정되면 다른 속성의 값도 결정되는 것을 말한다.(X → Y)
함수종속성의 종류
- 완전 함수 종속성 : 하나의 속성 그룹이 다른 속성 그룹에 대해 완전히 함수적으로 종속되어 있는 경우를 말함
- 부분 함수 종속성 : 어떤 속성 그룹이 다른 속성 그룹에 대해 부분적으로만 함수적으로 종속되어 있는 경우를 말함
- 이행적 함수 종속성 : 속성 그룹 간의 종속성이 체이닝 되어있는 경우. ex) X→Y, Y→Z일때 X →Z이다
함수종속성의 특징
- 데이터 베이스의 설계 : 함수 종속성을 분석하여 정규화를 수행하여 데이터 중복과 이상 현상을 최소화 할 수 있다.
- 쿼리 최적화 : 함수 종속성을 이해하면 쿼리의 조인과 필터링 조건을 최적화하여 데이터베이스의 성능을 향상시킨다.
정규화
- 정규화란 잘못 설계된 테이블을 수정하여 데이터의 일관성과 무결성을 회복하는 프로세스
- (중복성과 종속성을 제거(최소화) 데이터베이스의 효율성과 유지보수의 구조를 개선하고
- 데이터베이스의 성능 향상을 최적화하는데 의미가 있다.
주요 정규화 형식 제 1정규형 ~ 제 3정규형
- 제1정규형 : 테이블이 각 송성 값은 반복그룹이 없는 원자값으로만 구성되도록 중복되는 송성이나 속성 그룹을 별도의 테이블로 분리한다.
- 제2정규형 : 1NF를 만족하면서 부분 함수적 종속성을 제거해야 한다. 기본키 속성에 완전 함수적 종속성을 가짇록 테이블을 분할하거나 기본키를 변경하거나 속성간의 종속성을 조정.
- 제3정규형 : 2NF를 만족하면서 이행 함수적 종속성을 제거해야한다. 테이블의 모든 비(Non-key)속성은 기본키에만 종속되어야 하고, 비-키 속성간에는 종속성이 존재하지 않아야 한다.
만약 종속성이 존재한다면 테이블 분할해야 한다. - 반정규화(Denormalization) : 중복 데이터를 하나 이상의 테이블에 추가하는 데이터 베이스 최적화 기술 이를 통해 관계형 데이터베이스에서 비용이 많이 드는 조인의 수를 줄일 수 있다.
- 반정규화는 정규화를 되돌린다거나 정규화 되지않음을 의미하는 것이 아니라, 정규화 후에 적용되는 최적화기업
- 장점 : 더 적은 수의 테이블을 사용하면서 조인 개수를 줄일 수 있고, 이로 인해 검색 쿼리가 간단해지고 빠른 읽기 작업의 수행으로 검색성능이 좋아진다.
- 단점 : 중복 저장으로 더 많은 스토리지가 요구된다. 도한 데이터 불일치가 발생할 수 있으며, 쓰기 작업에 추가적은 비용이 발생할 수 있다.
'STUDY > DataBase' 카테고리의 다른 글
| [데이터베이스] 데이터 입출력 (Stream) (2) | 2024.01.30 |
|---|---|
| [데이터베이스] 8주차 교육 정리 (1) | 2024.01.24 |
| [데이터베이스] 7주차 교육 정리 (0) | 2024.01.24 |
| [데이터베이스] 데이터 모델링 (2) | 2024.01.24 |
| [데이터베이스] 관계대수 (1) | 2024.01.17 |