언어, 프레임워크/Spring

DB(H2) 사용 방식 / 드라이버와 dialect의 역할과 차이점 / 자바의 데이터 접근 기술 분류

go_getter 2025. 4. 30. 19:56

DB 사용 방식

1. Server Mode

- 컴퓨터에 DB 엔진을 설치해서 사용하는 방식

- 애플리케이션과 DB과 분리되어 있기 때문에 여러 애플리케이션이 동일한 DB 사용하기에 적합

- 배포 시에 사용

 

2. In-memory Mode

- 애플리케이션에 DB 엔진이 내장되어 있어, 애플리케이션과 함께 실행되고 종료되는 방식

- 애플리케이션이 종료되면 데이터가 휘발됨

- 단위 테스트 시에 사용

ex. h2

# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:{DB 이름}  //mem이 있으면 인메모리 방식
spring.datasource.username=sa
spring.datasource.password=

h2.console.enabled=true //h2-console 사용 여부
h2.console.path= /h2-console //localhost:8080/h2-console을 입력하면 브라우저로 DB 콘솔 사용 가능

DB_CLOSE_DELAY=-1 //을 url 제일 뒤에 추가하면 앱이 실행되는 동안 DB가 계속 열려있음
DB_CLOSE_ON_EXIT=FALSE //을 url 제일 뒤에 추가하면 앱이 종료될 때 DB의 자동 종료 방지
//=> h2-console에서 DB 조회를 하고 싶을 때 사용

 

3. Embedded Mode

- In-memory 모드와 동일하게 애플리케이션과 함께 실행되고 종료되는 방식

- 데이터를 로컬에 저장하기 때문에 애플리케이션을 종료해도 데이터가 휘발되지 않음

# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:{DB가 저장될 경로}
spring.datasource.username=sa
spring.datasource.password=

 


JDBC 드라이버의 역할

데이터베이스 드라이버는 애플리케이션과 데이터베이스 간의 통신을 중개하는 역할

다양한 데이터베이스 시스템(Oracle, MySQL, PostgreSQL)마다 호환되는 드라이버가 있다.




드라이버와 dialect의 차이점

dialect는 여러 DBMS가 애플리케이션과 호환될 수 있도록 변환해주는 역할을 한다고 했는데, 드라이버와 어떤 차이점이 있을까

 

드라이버의 주요 역할

- DB 연결 및 종료

- 쿼리 실행(excute), 결과 수신

- 자바 코드로 작성한 SQL을 DBMS가 이해할 수 있도록 변환하여 전달

- 데이터 타입 변환(VARCHAR <-> String, TIMESTAMP <-> LocalDateTime)

=> JDBC 드라이버는 물리적 통신과 데이터 전송/변환 담당

 

Dialect의 주요 역할

- DBMS별 SQL 문법 차이 처리(LIMIT/OFFSET, AUTO_INCREMENT, SEQUENCE, BOOLEAN)

- DB에 맞게 DDL 생성

- NOW(), SYSDATE 등 DB마다 다른 내장 함수 처리

=> Dialect는 SQL 문법 차이를 흡수하고, ORM이 DB 독립적으로 동작하도록 도움

 

결론적으로, 데이터 변환을 한다고 했을 때

타입 변환은 JDBC 드라이버가 처리하고, 문법/형식 변환은 Dialect가 처리한다.


JDBC Driver Manager의 런타임 시점 흐름도

 

Connection : 쿼리 요청을 위한 연결 생성

Statement : 쿼리 요청 가능한 상태로 변경

ResultSet : 쿼리 결과를 응답

 


JDBC / JDBC Template / MyBatis / ORM

1. JDBC (Java Database Connectivity) — 가장 원시적인 방식

  • 모든 DB 처리 코드 수동 작성
  • 자원 연결/해제, SQL 실행, 결과 매핑 모두 직접 수행해야 함
  • 코드가 길고 복잡함
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
stmt.setLong(1, id);
ResultSet rs = stmt.executeQuery();

User user = null;
if (rs.next()) {
    user = new User();
    user.setId(rs.getLong("id"));
    user.setName(rs.getString("name"));
}

rs.close();
stmt.close();
conn.close();

 

2. JdbcTemplate — JDBC 반복 코드 추상화

  • 자원 처리 자동화 (Connection, PreparedStatement, ResultSet 정리)
  • 결과 매핑은 RowMapper로 개발자가 작성해야 함
  • JDBC 보일러플레이트 제거만 해줌
public class UserRowMapper implements RowMapper<User> {
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setId(rs.getLong("id"));
        user.setName(rs.getString("name"));
        return user;
    }
}
User user = jdbcTemplate.queryForObject(
    "SELECT * FROM users WHERE id = ?",
    new Object[]{id},
    new UserRowMapper()
);

 

3. MyBatis — SQL Mapper 프레임워크

  • JDBC 기반 SQL Mapper 프레임워크로, 객체 매핑과 JDBC 반복 코드 자동화
  • SQL은 직접 작성 (자동화하되, SQL문은 직접 작성하고 싶을 때 사용)

실행 흐름

단계 구성요소 설명
1 SqlSessionFactoryBuilder mybatis-config.xml을 읽고 SqlSessionFactory 생성
2 mybatis-config.xml Type Alias, Mapper XML의 위치 설정
3 SqlSessionFactory SqlSession을 생성하는 팩토리 객체
4 SqlSession SQL을 실행할 수 있는 세션 객체
5 Mapper 인터페이스 SQL과 매핑되는 Java 인터페이스
6 Mapper XML SQL 정의 및 결과 매핑 파일 (UserMapper.xml)

// 2단계 :  /resources/mybatis-config.xml
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.thesun4sky.querymapper.domain"/>
    </typeAliases>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

두 가지 Mapper 사용 방식

방법 1: DAO + SqlSession 직접 사용

// Mapper Interface 대신 Dao 클래스 정의
@Component
public class UserDao {
    private final SqlSession sqlSession;

    public UserDao(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    public User selectUserById(long id) {
        return this.sqlSession.selectOne("selectUserById", id);
    }
}
// Mapper XML
<mapper namespace="UserDao">
    <select id="selectUserById" resultType="User">
        SELECT id, name FROM users WHERE id = #{id}
    </select>
</mapper>

 

방법 2: Mapper 인터페이스 사용 

// Mapper Interface 정의
@Mapper
public interface UserMapper {
    User selectUserById(@Param("id") Long id);
}
<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectUserById" resultType="User">
        SELECT id, name FROM users WHERE id = #{id}
    </select>
</mapper>

https://teamsparta.notion.site/3-RawJPA-49768671cced4fdd8a03cd72f55c41f1

4. ORM (JPA / Hibernate 등) — 완전 객체 중심 설계

  • SQL 작성 없이 객체만 정의하면 SQL 자동 생성
  • DB와 객체 간 상태 동기화
  • 복잡한 쿼리에는 JPQL 또는 NativeQuery 사용 가능
@Entity
public class User {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findById(Long id); // 쿼리 자동 생성
}
// 호출 코드
User user = userRepository.findById(1L).orElse(null);