TIL- Spring 이해(2)
2024-05-14
Create, Read 구현하기
- DTO란?
이름에서도 알 수 있듯이 DTO(Data Transfer Object)는 데이터 전송 및 이동을 위해 생성되는 객체를 의미
- Client에서 보내오는 데이터를 객체로 처리할 때 사용
- DB와의 소통을 담당하는 Java 클래스를 그대로 Client에 반환하는 것이 아니라 DTO로 한번 변환한 후 반환할 때도 사용
- Request의 데이터를 처리할 때 사용되는 객체는 RequestDto, Response를 할 때 사용되는 객체는 ResponseDto라는 이름을 붙여 DTO 클래스를 만들 수 있음.
- Create 구현
- 메모 데이터를 저장할 Memo 클래스 생성
- 메모 생성하기 API를 받을 수 있는 Controller와 메서드 생성
- Client에 데이터를 반환할 때 사용할 MemoResponseDto 클래스 생성
- Client의 요청 데이터를 받아줄 MemoRequestDto 클래스 생성
- DB와 연결을 하지 않았기 때문에 메모 데이터를 저장할 Java 컬렉션 생성
- 메모 생성 로직 작성
- Read 구현
- DB 역할을 하는 memoList를 조회하여 List
로 변환한 후 반환
- DB 역할을 하는 memoList를 조회하여 List
Database
Database를 한 마디로 정의하면 ‘데이터의 집합’
DBMS : DBMS 는 ‘Database Management System’ 의 약자로 Database를 관리하고 운영하는 소프트웨어를 의미
RDBMS : RDBMS는 ‘Relational DBMS’의 약자로 관계형 데이터베이스, 테이블(table)이라는 최소 단위로 구성되며, 이 테이블은 열(column)과 행(row)으로 이루어져 있음. 테이블간 FK(Foreign Key)를 통해 다른 데이터를 조합해서 함께 볼수 있다라는 장점.
RDBMS의 종류 : 유료인 Oracle을 제외하고 보통 MySQL, PostgreSQL 중에서 많이 고르는 편인데, 우리는 MySQL을 사용
MySQL
- MySQL은 우리가 서비스를 배포할 때 사용할 데이터베이스
- AWS RDS 라는 서비스를 사용해 붙여볼 예정
- Spring과 궁합이 좋아서 많은 회사에서 사용
SQL
SQL은 ‘Structured Query Language’ 의 약자로 RDBMS에서 사용되는 언어, 수 많은 정보를 Database에서 조작하고 관리하기 위해서는 SQL 언어를 사용 해야함.
국제표준화기구에서 SQL에 대한 표준을 정해서 발표하고 있지만 DBMS를 만드는 회사가 여러 곳이기 때문에 DBMS 마다 표준 SQL을 준수하되, 각 제품의 특성을 반영하기 위한 약간의 차이가 존재
- DDL
‘Data Definition Language’ 의 약자로 테이블이나 관계의 구조를 생성하는데 사용
- CREATE : 새로운 데이터베이스 및 테이블을 생성
- ALTER : 데이터베이스와 테이블의 내용을 수정
- DROP : 데이터베이스와 테이블을 삭제, 데이터 및 테이블 전체를 삭제
- TRUNCATE : 데이터베이스와 테이블을 삭제할 수 있음. 최초 테이블이 만들어졌던 상태 즉, 컬럼값만 남김
- DCL
- ‘Data Control Language’ 의 약자로 데이터의 사용 권한을 관리하는데 사용
GRANT : 사용자 또는 ROLE에 대해 권한을 부여
- EVOKE : 사용자 또는 ROLE에 부여한 권한을 회수
- DML
‘Data Manipulation Language’ 의 약자로 테이블에 데이터를 검색, 삽입, 수정, 삭제하는데 사용
- INSERT : 테이블에 새로운 row를 추가
- SELECT : 테이블의 row를 선택
- UPDATE : 테이블의 row의 내용을 수정
- DELETE : 테이블의 row를 삭제
- CREATE
- 제약조건
AUTO_INCREMENT : 컬럼의 값이 중복되지 않게 1씩 자동으로 증가하게 해줘 고유번호를 생성해 줌
CREATE TABLE 테이블이름 ( 필드이름 필드타입 AUTO_INCREMENT, // id bigint AUTO_INCREMENT, ... );
NOT NULL : 해당 필드는 NULL 값을 저장할 수 없게 됨.
CREATE TABLE 테이블이름 ( 필드이름 필드타입 NOT NULL, ... );
- UNIQUE : 해당 필드는 서로 다른 값을 가져야만 함.
- PRIMARY KEY : 해당 필드가 NOT NULL과 UNIQUE 제약 조건의 특징을 모두 가지게 됨
- FOREIGN KEY : 하나의 테이블을 다른 테이블에 의존하게 만들며 데이터의 무결성을 보장함
- CASCADE : FOREIGN KEY 로 연관된 데이터를 삭제,변경할 수 있음
- 제약조건
📌 JOIN 이해하기
JOIN은 나누어진 테이블을 하나로 합치기 위해 데이터베이스가 제공하는 기능.
JOIN 은 ON 이라는 키워드를 통해 기준이 되는 컬럼을 선택하여 2개의 테이블을 합쳐줌.
JOIN을 할 때에는 적어도 하나의 컬럼을 서로 공유하고 있어야 하기 때문에 테이블에 외래 키가 설정 되어 있다면 해당 컬럼을 통해 JOIN을 하면 조건을 충족할 수 있음.
❗️다만 JOIN을 하기 위해 외래 키를 설정하는 것이 항상 좋은 선택이 아닐 수도 있음
- 외래 키를 설정하면 데이터 무결성을 확인하는 추가 연산이 발생.
- 또한 무결성을 지켜야하기 때문에 상황에 따라 개발하는데 불편할 수 있음.
👉 결론은 항상 테이블에 모든 제약조건을 걸어야 하는 것은 아니며 프로젝트의 상황에 따라 가장 효율적인 제약조건을 테이블에 적용해야함.
JDBC
- 등장배경
- 우선 DB에 연결하기 위해 커넥션을 연결해야함.
- SQL을 작성한 후 커넥션을 통해 SQL을 요청함.
- 요청한 SQL에 대한 결과를 응답 받음.
- 기존에 사용하던 MySQL 서버를 PostgreSQL 서버로 변경한다면 무슨일이 발생할까?
MySQL과 PostgreSQL은 커넥션을 연결하는 방법, SQL을 전달하는 방법, 결과를 응답받는 방법 모두 다를 수 있음.
- 따라서 애플리케이션 서버에서 작성했던 DB 연결 로직들을 전부 수정해야함.
- 이러한 문제를 해결하기위해 JDBC 표준 인터페이스가 등장했음.
- JDBC는 Java Database Connectivity로 DB에 접근할 수 있도록 Java에서 제공하는 API
- JDBC에 연결해야하는 DB의 JDBC 드라이버를 제공하면 DB 연결 로직을 변경할 필요없이 DB 변경이 가능
- DB 회사들은 자신들의 DB에 맞도록 JDBC 인터페이스를 구현한 후 라이브러리로 제공하는데 이를 JDBC 드라이버라 부름
- 따라서, MySQL 드라이버를 사용해 DB에 연결을 하다 PostgreSQL 서버로 변경이 필요할 때 드라이버만 교체하면 손쉽게 DB 변경이 가능
- JdbcTemplate이란? - JDBC의 등장으로 손쉽게 DB교체가 가능해졌지만 아직도 DB에 연결하기 위해 여러가지 작업 로직들을 직접 작성해야한다는 불편함이 남아있음. - 이러한 불편함을 해결하기 위해 커넥션 연결, statement 준비 및 실행, 커넥션 종료 등의 반복적이고 중복되는 작업들을 대신 처리해주는 JdbcTemplate이 등장
- 정리 : RDBMS 데이터 테이블에서 컬럼 하나는 자바 객체 클래스에서 필드 하나와 매칭, 테이블에서 데이터 한 줄은 클래스의 객체 하나가 됨.
1주차 숙제 모르는 부분 정리
CREATE TABLE IF NOT EXISTS
: “MANAGER”라는 이름의 테이블을 만들고, 만약 이미 존재한다면 다시 만들지 않고 그대로 둠.여기서
IF NOT EXISTS은 DB
객체를 생성할 때 해당 객체가 이미 존재하는지 확인하는 역할. 객체가 존재하지 않을 때만 해당 객체를 생성.AUTO_INCREMENT
: 테이블에 새로운 레코드를 추가할 때 사용. 테이블의 특정 열에 대해 자동으로 값을 증가시키는 역할을 하고 주요 키(primary key)로 사용되는 열에 적용ALTER TABLE EXAM DROP CONSTRAINT exam_fk_student_code;
: 이전에 설정된 외래키 제약 조건을 제거ALTER TABLE EXAM ADD CONSTRAINT exam_fk_student_code FOREIGN KEY(student_code) REFERENCES STUDENT(student_code) ON DELETE CASCADE;
: EXAM 테이블에 새로운 외래키 제약 조건을 추가. 이 왜래키는 student_code 열을 참조하여 STUDENT 테이블의 student_code 열에 있는 값과 일치해야 함. “ON DELETE CASCADE” 옵션은 해당 학생의 레코드가 삭제될 때 “EXAM” 테이블의 관련된 모든 레코드도 자동으로 삭제
DELETE FROM STUDENT WHERE student_code = 's1';
: 이 명령은 “STUDENT” 테이블에서 “student_code” 값이 ‘s1’인 레코드를 삭제. 이는 특정 학생의 레코드를 데이터베이스에서 완전히 제거함.
1주차 프로젝트 문제점
- 현재 우리가 작성한 메모장 프로젝트는 Controller 클래스 하나로 모든 API를 처리하고 있음.
현재는 API 수가 적고 기능이 단순하여 코드가 복잡해 보이지 않을 수 있지만 앞으로 기능이 추가되고 복잡해진다면 문제가 발생할 수 있음.
- 한 개의 클래스에 너무 많은 양의 코드가 존재하기 때문에 코드를 이해하기 어려움.
- 현업에서는 코드의 추가 혹은 변경 요청이 계속 생길 수 있음.
- 문제가 발생했는데 해당 Controller 클래스를 구현한 개발자가 퇴사한다면?
- Spring의 3 Layer Architecture
- 이러한 문제점들을 해결하기 위해 서버 개발자들은 서버에서의 처리과정이 대부분 비슷하다는 걸 깨닫고, 처리 과정을 크게 Controller, Service, Repository 3개로 분리함.
chrome 브라우저에서 게시글을 작성하는 요청(Request)를 함. HTTP 프로토콜 request 규칙에 맞춰 Controller에 들어오게 됨.
- Controller에서 요청을 받은 다음 바로 Service 로 전달함. Service는 요청을 받아 구현함(게시글을 저장하는 로직을 코드로 작성) 완료되면 Repository에 전달함.
- Repository가 가공이 된 데이터를 받아서 DB와 연결을 해서 해당 데이터를 저장함.
- 저장을 하고 난 다음 예를들어 게시글의 고유키를 받아와서 전달을 하려고 Repository가 PK를 Service에게 전달하고 Service가 PK를 받아 Controller에게 전달함. Controller는 해당 데이터를 Client 즉. 브라우저에게 전달함.
IoC(제어의 역전), DI(의존성 주입)
- IoC, DI는 객체지향의 SOLID 원칙 그리고 GoF 의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴
IoC는 설계 원칙에 해당하고 DI는 디자인 패턴에 해당
- 김치 볶음밥 맛있게 만드는 방법 (설계 원칙)
- 김치 볶음밥 레시피 (디자인 패턴)
- 오일을 두른 팬에 채썬 파를 볶아 파기름을 만든다.
- 준비한 햄을 넣고 볶다가, 간장 한스푼을 넣어 풍미를 낸다.
- 설탕에 버무린 김치를 넣고 함께 볶는다.
- 미리 식혀 둔 밥을 넣어 함께 볶는다.
- 참기름 한스푼을 넣어 마무리한다
- 좋은 코드란 무엇일까?
논리가 간단해야 한다.
- 중복을 제거하고 표현을 명확하게 한다.
- 코드를 처음 보는 사람도 쉽게 이해하고 수정할 수 있어야 한다.
- 의존성을 최소화해야 한다.
- 새로운 기능을 추가 하더라도 크게 구조의 변경이 없어야 한다.
- Spring 의 핵심 기술을 소개하는 Docs에서 가장 처음으로 IoC 컨테이너에 대해서 설명하고 있음.
- 그리고 IoC에 대해 ‘IoC는 DI로도 알려져 있다’ 라고 소개하고 있음.
의역해보자면 ‘DI 패턴을 사용하여 IoC 설계 원칙을 구현하고 있다’ 라고 이해하시면 좋을 것 같음.
- 의존성이란?
- 예를들어 우리가 다리를 다쳐서 목발을 사용하여 걷게 된다면 우리는 걷기 위해 목발에 의존하고 있는 것. 즉, 우리는 목발에 의존성을 두게 되었다고 할 수 있음.
- 강한 결합
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Consumer {
void eat() {
Chicken chicken = new Chicken();
chicken.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat();
}
}
class Chicken {
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
- 만약 Consumer 가 치킨이 아니라 피자를 먹고 싶어 한다면? 많은 수의 코드 변경이 불가피
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
consumer.eat(new Pizza());
}
}
interface Food {
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
interface 다형성 원리를 사용하여 해결, 약한 결합, 약한 의존성
- 주입이란?
- 우리가 주사기를 통해 백신을 우리 몸속에 주입 하듯이
- 코드에서의 주입도 마찬가지로 여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것
- 제어의 역전이란?
- 이전에는 Consumer가 직접 Food를 만들어 먹었기 때문에 새로운 Food를 만들려면 추가적인 요리준비(코드변경)가 불가피했음.
그렇기 때문에 이때는 제어의 흐름이 Consumer → Food 였음.
- 이를 해결하기 위해 만들어진 Food를 Consumer에게 전달해주는 식으로 변경함으로써 Consumer는 추가적인 요리준비(코드변경) 없이 어느 Food가 되었든지 전부 먹을 수 있게 됨
- 결과적으로 제어의 흐름이 Food → Consumer 로 역전
- JPA
- Java ORM 기술의 대표적인 표준 명세
- 하이버네이트(Hibernate)란?
- JPA 는 표준 명세이고, 이를 실제 구현한 프레임워크 중 사실상 표준이 하이버네이트
- Entity
- JAP에서 관리되는 클래스 즉, 객체를 의미
- Entitiy 클래스는 DB의 테이블과 매핑되어 JPA에 의해 관리됨
추가 🕤
자바의 창시자인 제임스 고슬링이 자바 커피를 매우 좋아했다고 해요. 커피를 막 10잔씩도 마셨다고.. 자바 커피 매니아로서 자바라는 명칭도 커피 지배지인 인도네시아 섬인 자바에서 따왔다고 해요. 오늘 수업을 들으며 빈(Bean)에 대해 학습하며 커피 콩 모양이 너무 귀여웠어요.. 아마 자바 커피와 맞춘 거 같다고..하신..
꼭 이런 공부에 관련 없는 것만 기억을 잘 해요..DI를 사용하려면 객체 생성이 우선 되어야 하죠? Spring 프레임워크가 필요한 객체를 생성하고 관리하는 역할을 대신 해준다고 해요. 여기서 빈(Bean)은 Spring이 관리하는 객체라고 합니다!
- 자바 커피를 맛보고 싶네요.
🐱🏍— —🤸🏻♀️ ~~~ 야~호~