본문 바로가기
Spring

[Spring] JDBC란 무엇이고 어떻게 사용할까?

by worldcenter 2024. 9. 30.

JDBC의 등장 배경

 

애플리케이션 서버에서 DB에 접근하기 위해서는 여러가지 작업이 필요합니다.

1. 우선 DB에 연결하기 위해 Connection이 필요합니다.

2. SQL을 작성한 후 Connection을 통해 SQL을 요청합니다.

3. 요청한 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이 등장 했습니다.

 

JdbcTemplate  사용 방법

1. application.properties에 DB에 접근하기 위한 정보를 작성합니다.

spring.application.name=memospring.datasource.url=jdbc:mysql://localhost:3306/memospring.datasource.username=root
spring.datasource.password=[패스워드]
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

 

2. build.gradle에 JDBC 라이브러리와 MySQL을 등록합니다.

dependencies {
    implementation 'mysql:mysql-connector-java:8.0.28'
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    ...
}

 

3. DB 연결이 필요한 곳에서 JdbcTemplate을 주입 받아와 사용합니다.

@RestController
@RequestMapping("/api")
public class MemoController {

    // DB 대신 사용
    private final JdbcTemplate jdbcTemplate;

    // JDBC 초기화
    public MemoController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

 

4. UPDATE 구현

@RestController
@RequestMapping("/api")
public class MemoController {

    // DB 대신 사용
    private final JdbcTemplate jdbcTemplate;

    // JDBC 초기화
    public MemoController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);

        // DB 저장
        KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체

        String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
        jdbcTemplate.update(con -> {
            PreparedStatement preparedStatement = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            preparedStatement.setString(1, memo.getUsername());
            preparedStatement.setString(2, memo.getContents());
            return  preparedStatement;
        }, keyHolder);

        // DB Insert 후 받아온 기본 키 확인
        Long id = keyHolder.getKey().longValue();
        memo.setId(id);

        // Entity -> ResponseDto
        MemoResponseDto memoResponseDto = new MemoResponseDto(memo);

        return memoResponseDto;

    }

 

ID 값이 AUTO_INCREMENT 인 경우, Insert 쿼리 실행 시 ID 값을 value로 직접 지정해주지 않는다. (왜냐하면? 자동 생성되기 때문!)

그런데, 어떠한 엔티티를 테이블에 삽입하고 나서 그 엔티티에게 할당된 아이디 값을 전달받고 싶은 경우에는 어떻게 해야할까?

JDBCTemplate은 자동으로 생성된 키 값을 구할 수 있는 방법을 제공하는데, 그것은 바로 KeyHolder이다.

 

jdbcTemplate.update() 메서드는 INSERT, UPDATE, DELETE와 같이 생성, 수정, 삭제에 사용될 수 있는데 PreparedStatement와 KeyHolder 객체를 파라미터로 갖습니다.