Today I Learned
#SQL과 JDBC, 그리고 H2 실습으로 배우는 데이터베이스의 본질
단순히 JPA를 사용하는 수준을 넘어서, 그 기초가 되는 기술들 SQL, JDBC, H2 데이터베이스를 직접 다뤄보았다.
실습 중심의 구성을 통해 문법을 배우는 것이 아니라 왜 그렇게 동작하는지를 익힐 수 있었다.
H2 데이터베이스란?
H2는 Java 기반의 경량형 관계형 데이터베이스로, 테스트나 로컬 개발 환경에서 자주 사용된다.
특히 Spring Boot와의 궁합이 좋아서, JPA 학습이나 단위 테스트에 매우 유용하다.
- Embedded Mode: 로컬 파일(`.mv.db`)로 데이터 저장
- In-memory Mode: 메모리에만 존재, 테스트용
- Server Mode: 외부 서버로 구동, 배포용
이번 실습에서는 Embedded Mode를 사용해 `~/test` 경로에 DB를 생성하고, H2 Console을 통해 직접 접속해보았다.
주요 기능 및 실습 흐름
1. SQL 문법 실습
SQL은 데이터베이스와 소통하는 언어이다. 이번 실습에서는 다음과 같은 문법을 직접 작성해보았다.
- DDL (정의): CREATE TABLE, ALTER TABLE, DROP TABLE
- DML (조작): INSERT, SELECT, UPDATE, DELETE
- DCL (제어): COMMIT, ROLLBACK, GRANT, REVOKE
- JOIN / GROUP BY / ORDER BY: 복잡한 데이터 연결 및 집계
예시: 사용자 테이블 생성 후, 게시글과 댓글 테이블을 JOIN하여 조회
2. JDBC 실습
JPA는 내부적으로 JDBC를 사용해 DB와 통신한다.
이번 실습에서는 JDBC를 직접 다뤄보며 그 구조를 이해했다.
- `Connection`, `Statement`, `ResultSet` 등 핵심 객체 사용
- `PreparedStatement`로 SQL Injection 방지 및 성능 향상
- Java 코드로 직접 DB 연결 및 CRUD 구현
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, 1);
ResultSet rs = pstmt.executeQuery();
3. JdbcTemplate 활용
Spring Boot에서는 `JdbcTemplate`을 통해 SQL을 더 간편하게 실행할 수 있다.
- `query()`, `update()` 메서드로 SQL 실행
- `RowMapper`를 통해 결과를 객체로 매핑
- 사용자 목록 조회, 단일 사용자 조회 등 실습
List<User> users = jdbcTemplate.query("SELECT * FROM users", new UserRowMapper());
#Raw JPA와 Entity 설계의 본질
1. QueryMapper와 MyBatis 이해
QueryMapper란?
- SQL을 XML 파일로 분리해 관리하는 방식
- 코드와 쿼리를 분리해 가독성과 유지보수 향상
MyBatis 등장 배경
- 반복되는 JDBC 코드 제거
- SQL 중심 개발을 위한 Mapper 구조 제공
실행 흐름
- SqlSessionFactory → SqlSession → Mapper Interface → XML 쿼리 실행
2. ORM의 등장과 해결 과제
ORM이 해결해야 할 문제들
- 객체와 테이블 간의 상속, 관계, 탐색, 식별성 불일치
JPA의 해결 방식
- `@OneToMany`, `@ManyToOne`, `@JoinColumn`, @Embedded`, `@Id`, `@GeneratedValue` 등 다양한 어노테이션으로 매핑
영속성 컨텍스트와 쓰기 지연
- `persist()` → `flush()` → `commit()` 순으로 DB 반영
- 여러 객체를 한번에 처리해 성능 최적화
3. 🛠️ JpaRepository와 Entity 설계
JpaRepository 사용법
- `JpaRepository<Entity, ID>` 인터페이스 상속만으로 CRUD 자동 구현
Entity 클래스 설계
- `@Entity`, `@Table`, `@Id`, `@Column` 등으로 필드 매핑
- `@Builder`, `@NoArgsConstructor`, `@Getter` 등 Lombok 활용
- 연관관계는 `@OneToMany`, `@ManyToOne` 등으로 정의
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
@OneToMany
private Set<UserChannel> userChannel;
}
4. 연관관계 매핑 실습
일대일 (`@OneToOne`)
- 단방향 / 양방향 모두 가능
일대다 (`@OneToMany`)
- 단방향은 `@JoinColumn`, 양방향은 `mappedBy` 사용
다대일 (`@ManyToOne`)
- `fetch = LAZY` 설정 권장
다대다 (`@ManyToMany`)
- 실무에서는 중간 매핑 테이블을 직접 정의해 관리
@ManyToMany
@JoinTable(
name = "parent_child",
joinColumns = @JoinColumn(name = "parent_id"),
inverseJoinColumns = @JoinColumn(name = "child_id")
)
private List<Child> children;
5. Embedded 타입과 복합 필드 매핑
복합 필드 매핑
- `@Embeddable` + `@Embedded`로 객체 필드를 테이블 컬럼에 매핑
- `@AttributeOverride`로 컬럼명 커스터마이징 가능
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "home_city")),
@AttributeOverride(name = "street", column = @Column(name = "home_street"))
})
private Address homeAddress;
#마치며
이번 학습은 단순히 JPA를 사용하는 것이 아니라, JPA가 왜 필요한지, 어떤 문제를 해결하려고 등장했는지, 그리고 그 내부에서 어떤 기술들이 작동하고 있는지를 실습을 통해 직접 체험할 수 있는 시간이었다.
SQL과 JDBC를 손으로 다뤄보니, ORM이 얼마나 많은 복잡성을 감추고 있는지 새삼 느껴졌고, Entity 설계와 연관관계 매핑을 통해 객체 지향적인 데이터 모델링의 중요성도 깊이 이해할 수 있었다.
다음 학습을 위해 이번 내용을 탄탄히 다져두면 훨씬 수월하게 따라갈 수 있을 것 같다.