Contents
4. 테이블 생성 4. 테이블 생성
데이터베이스에 요청할 게시글 테이블을 만들어보자.
4-1. 동작 구조
동작 구조는 크게 아래와 같다.

클라이언트(브라우저) → Controller → Repository → DB 순서로 클라이언트의 요청이 이동한다.
브라우저는 Controller 에 의존하고, Controller 는 Repository 에 의존하고, Repository 는 DB 에 의존한다.
4-2. H2 Database 사용법
데이터베이스는 영구히 기록될 수 있어야 한다. (=커밋(Commit)되어야 한다.) 메모리에 있는 것을 하드디스크에 넣을 때, 커밋 된다.
이번에 사용해 볼 H2 는 메모리 DB 로, 테스트용 DB 이다.
스프링(프레임워크)이 켜질 때, H2 를 실행 시킬거고, 스프링이 꺼지면 같이 날라가는 녀석이다. 매번 서버를 재시작 할 때마다 초기화 된다.
테스트가 다 끝나면 실제 데이터베이스에 넣으면 되니, 문제 없다.
항상 일관된 상태에서 테스트 해 볼 수 있다는 장점이 있겠다.
4-2-1. 라이브러리
build.gradle 에서 확인 할 수 있는 라이브러리

runtimeOnly 'com.h2database:h2'
4-2-2. application 설정하기
application.properties 에서 아래와 같이 데이터베이스를 세팅해주어야 한다.

빨간 박스의 값은 고정이다.
spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:test spring.datasource.username=sa
4-2-3. DB 접속해보기
H2 Database 라이브러리가 존재하니, 브라우저 주소창에 빨간 박스 내용을 입력하면(localhost:8080/h2-console) h2 의 존재유무를 눈으로 확인 할 수 있다.

JDBC URL: 을 설정하고 서버재실행 했음에도 이전의 URL 이 바뀌지 않으면, 위와 같이 직접 값을 넣어서 바꿔주면 된다. 그리고 Connect.
4-3. 자바에서 DB 데이터 작업하기
- JDBC 사용

자바 애플리케이션은 JDBC(Java Database Connectivity) API 를 사용하여 자바 애플리케이션에서 SQL 쿼리를 실행하고, 데이터베이스로부터 데이터를 가져오거나 데이터를 삽입, 업데이트, 삭제하는 등의 작업을 할 수 있다.
‘SELECT’, ‘UPDATE’, ‘DELETE’, ‘INSERT’
DBMS(Database Management System) 는 데이터베이스를 관리하는 소프트웨어로, 데이터의 저장, 수정, 삭제, 조회 등 데이터베이스와 관련된 모든 작업을 처리한다.

자바에서 SQL 쿼리를 사용하여 DBMS 에 필요한 정보를 요청하고, DBMS 가 DB 의 내용을 가져와서 Java 로 리턴 해준다.
이 때, 데이터를 조회 할 때 사용되는 ‘SELECT’ 를 제외한, 나머지 명령문은 데이터 조회 값을 리턴 해 줄 필요가 없기 때문에 쿼리로 영향을 받은 행(row)의 개수를 나타내는 ‘int’ 값을 반환한다.
ex. ‘INSERT’ 요청하면 DB에 write 요청하고, 성공하면 잘됐어~하는 결과 값 int 만 리턴 해주는 것이다.
자바 애플리케이션이 데이터베이스에 연결할 때마다 새로운 연결(Connection)이 생성되고, 사용된 후 닫히는 작업이 반복되는데, 이러한 연결 생성과 종료의 비용을 줄이기 위해 JDBC 는 DataSource 를 통해 연결을 관리한다. DataSource는 연결을 미리 생성해두고 필요할 때 빌려주는 방식으로 동작한다. 두 개의 쿼리 요청이 들어오면 두 개가 리턴 된다.
DBMS 의 데이터 타입은 테이블 타입으로(VARCHAR, INT, DATE), 자바와는 타입이 다르다.
SQL 쿼리 조회 ‘SELECT’ 의 결과는 테이블 형식으로 반환 되며, 자바에서는 이 결과를 Result 객체로 받아온다. ResultSet 은 테이블 형식의 데이터를 다루기 때문에, 쿼리 결과를 자바 객체로 매핑(mapping)하여 사용한다.

리턴 되는 테이블 타입을 자바에서 객체의 속성에 접근하는 방법대로 . 으로 접근해서 쓰질 못하니, 객체를 만들어서 사용해야 한다는 것.
ResultSet 의 데이터를 담으려면 행의 수만큼 객체가 필요하다. 커서를 내리는 행마다 new 객체가 만들어져야 한다. 위의 예시로는 객체가 3개는 필요한 셈이다.
class A {
int id;
String title;
}
- 데이터베이스 프레임워크 사용 (MyBatis 와 Hibernate)
테이블 형태 → 자바 객체로 매핑을 자동으로 DataSource 가 해주지 않기 때문에, 자바에서 rs.getInt(”id”) , rs.getString(”title”) 로 객체 매핑을 직접 했어야 했다.

매핑하고, 분석하고 클래스로 만들어내야 하는 몹시도 귀찮은 일을 하지 않기 위해
DB 프레임워크인 MyBatis 와 Hibernate 를 사용해보자.
객체 매핑을 자동으로 해주는게 MyBatis 와 Hibernate 이다. 오브젝트 매핑(하이버네이트는 ORM)
마이바티스/하이버네이트는 데이터베이스를 기본으로 깔고 있고 + 오브젝트 매핑까지 해주니, 여기서 JDBC 는 안쓸거임.
4-3-1. 하이버네이트 세팅
application.properties 에 가서 아래와 같이 하이버네이트를 세팅한다.

create 하면 자바에서 테이블을 만들고, DB(h2)에 만들어진 것을 확인 할 수 있다.
아래와 같이 none 으로 값을 바꾸면, 테이블이 안만들어진다.

주의) production 환경(서비스 환경)에서는 못 쓴다. 테스트 할 때 create 로 쓰다가 배포할 때에는 꼭 none 으로 바꿔줘야 한다. 배포할 때는 데이터베이스 my sql 만들고 테이블 만들고 직접 써야한다.
4-3-2. Board 테이블 만들기
Board 클래스를 만들어, 아래의 어노테이션을 다 붙여준다.
Lombok @Setter @Getter 를 붙이면, 내가 직접 만들어야하는 수고를 덜어준다.

빌더 패턴을 만들자. 단축키 alt + insert 로 생성자를 만들고, @Builder 어노테이션을 붙여준다.

한번 더 정리하자면, 자바 세상은 클래스 세상<> 데이터베이스 세상 - 테이블 타입
서로 저장하는 자료형이 다르고, 다른 언어니까 타입 이해를 할 수 없다.
서로 이해를 못하는 타입끼리는 전송 받으면 자기 타입으로 바꿔야한다. 이것은 통신에서 제일 기본. 데이터를 받으면 내가 쓸 수 있는 타입으로 변경하여야 한다.
오브젝트 매핑은 하이버네이트가 옮겨주는 것이다. myBatis 나 하이버네이트를 쓰면 자기가 자동으로 옮겨주는 것이다.
그럼 왜 에러가 나는걸까?

자바 애플리케이션이 SELECT 요청을 했어, sql 에서는 ‘테이블 데이터’로 응답해주잖아
자바 프로그램이 바로 받는 게 JDBC 였는데, 지금은 하이버네이트가 받는다.
하이버네이트가 중간에 끼어서 SELECT 요청을 대신 해줘, 대리인 역할을 해줘 , 테이블 데이터도 하이버네이트가 받는다.
테이블 데이터랑 똑같이 생긴 자바 데이터가 없나? 스캔을 쫙 함, 이 때, @Entity 라고 적혀있는애만 스캔을 쫙 한다.
하이버네이트가 Board 객체를 new 하고, new 해서 setter 로 다 집어넣는다.
지금은 어떻게 동작하지만 알면 된다.
자바 애플리케이션 → 하이버네이트(, my batis 데이터베이스 프레임워크) → 테이블 데이터 → 하이버네이트로 응답 받아서 오브젝트 매핑해줌 → How? Board 를 new 해줌. 빈 생성자가 만들어져서 값이 null 인데 DB 에서 조회받아서 쏙쏙 만들어넣음 (오브젝트 매핑) → 그걸 자바한테 주는거임
면접질문) entity 써봤네욥 디폴트 컨스트럭터가 왜 필요한지요? 하이버네이트가 빈객체를 new 해서 데이터를 오브젝트 매핑 해주기 때문입니다.
왜 하이버네이트는 디폴트를 때릴까? 빈 생성자 때리는건 쉽잖아~
빈 생성자를 만들어주는 어노테이션도 붙여주자.
@NoArgsConstructor // 빈 생성자 (하이버네이트가 om(object mapping 할때 필요)

어노테이션을 사용해서 기본생성자를 만들어주면, 에러는 사라진다.
하지만, 이건 tool 이 좋아서 에러가 뜨고 잡을 수 있었던거지, 이것은 컴파일러가 잡아주는 에러가 아니기 때문에 알고 있어야한다.
package shop.mtcoding.blog2.board;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.sql.Timestamp;
@NoArgsConstructor // 빈 생성자 (하이버네이트가 om(object mapping 할 때 필요)
@Getter
@Setter
@Table(name = "board_tb")
@Entity // DB에서 조회하면 자동 매핑이됨
public class Board {
// id 가 1씩 증가되는게 설정됨
@GeneratedValue(strategy = GenerationType.IDENTITY) // Auto_increment 설정, 시퀀스 설정
@Id // PK 설정 primary key 가 설정
private Integer id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
private Timestamp createdAt;
@Builder
public Board(Integer id, String title, String content, Timestamp createdAt) {
this.id = id;
this.title = title;
this.content = content;
this.createdAt = createdAt;
}
}
하고 실행해보면

문제 없이 콘솔창/로그 에 create 된 것을 확인 할 수 있다.
Share article