Spring 입문주차/1주차

20. JDBC란 무엇일까

note994 2024. 8. 15. 12:40

JDBC의 등장배경

 

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

1. 우선 DB에 연결하기 위해 커넥션을 연결해야 한다.

2. SQL을 작성한 후 커넥션을 통해 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에 연결을 하다 PostgresSQL 서버로 변경이 필요할 때 드라이버만 교체하면 손쉽게 DB변경이 가능하다.


JdbcTemplate이란?

JDBC의 등장으로 손쉽게 DB교체가 가능해졌지만 아직도 DB에 연결하기 위해 여러가지 작업 로직들을 직접 작성해야한다는 불편함이 남았다.

이러한 불편함을 해결하기 위해 커넥션 연결, statement 준비 및 실행, 커넥션 종료 등의 반복적이고 중복되는 작업들을 대신 처리해주는 JdbcTemplate이 등장했다.


JdbcTemplate 사용방법

이전에 진행하던 Memo 프로젝트에 들어간다.

resources에 있는 application.properties로 이동

 

이 코드들을 추가한다.

 

{비밀번호}는 우리의 데이터베이스 root 비밀번호를 입력한다. { } 기호로 감싸지 않는다.

 

지금 빨간색으로 오류가 난 부분을 해결해보자

 

build.gradle에 들어간다

 

위 코드를 추가하고 오른쪽 상단에 코끼리모양 새로고침 표시가 뜰텐데 그걸 눌러서 리빌딩을 해준다.

 

이 코드는 MySQL 드라이버를 가져오고 jdbc를 사용하는것이다.

 memo 데이터베이스를 생성한다.

Database 아이콘 클릭 - Data Source - MySQL

 

빨간 박스가 내가 손댄 부분이다.

memo 테이블 만들기

 

MemoController.java에 들어가서 이미 있던 내용을 싹 지우고 아래 코드를 삽입

package com.sparta.memo.controller;

import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.web.bind.annotation.*;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

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

    private final JdbcTemplate jdbcTemplate;

    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;
    }

    @GetMapping("/memos")
    public List<MemoResponseDto> getMemos() {
        // DB 조회
        String sql = "SELECT * FROM memo";

        return jdbcTemplate.query(sql, new RowMapper<MemoResponseDto>() {
            @Override
            public MemoResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
                // SQL 의 결과로 받아온 Memo 데이터들을 MemoResponseDto 타입으로 변환해줄 메서드
                Long id = rs.getLong("id");
                String username = rs.getString("username");
                String contents = rs.getString("contents");
                return new MemoResponseDto(id, username, contents);
            }
        });
    }

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findById(id);
        if(memo != null) {
            // memo 내용 수정
            String sql = "UPDATE memo SET username = ?, contents = ? WHERE id = ?";
            jdbcTemplate.update(sql, requestDto.getUsername(), requestDto.getContents(), id);

            return id;
        } else {
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
        }
    }

    @DeleteMapping("/memos/{id}")
    public Long deleteMemo(@PathVariable Long id) {
        // 해당 메모가 DB에 존재하는지 확인
        Memo memo = findById(id);
        if(memo != null) {
						// memo 삭제
            String sql = "DELETE FROM memo WHERE id = ?";
            jdbcTemplate.update(sql, id);

            return id;
        } else {
            throw new IllegalArgumentException("선택한 메모는 존재하지 않습니다.");
        }
    }

    private Memo findById(Long id) {
        // DB 조회
        String sql = "SELECT * FROM memo WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if(resultSet.next()) {
                Memo memo = new Memo();
                memo.setUsername(resultSet.getString("username"));
                memo.setContents(resultSet.getString("contents"));
                return memo;
            } else {
                return null;
            }
        }, id);
    }
}

JdbcTemplate를 사용하기 위한 코드 (MemoController 클래스 내부)


DB 저장

36번째 줄의 ?, ? 부분은 각각 41번째 42번째 줄에서 반환받은 값을 넣는 부분이다.


DB 조회

.MemoResponseDto 객체가 행의 개수만큼 생성된다. mapRow 함수는 조회할 데이터의 개수만큼 반복실행된다.

 

만약 10개를 조회해야 한다면 10개를 List로 묶어서 반환하는 코드이다.

 


UPDATE


DELETE


findById 메서드

 

'Spring 입문주차 > 1주차' 카테고리의 다른 글

19. SQL 연습하기  (0) 2024.08.14
18. SQL  (0) 2024.08.14
17. Database  (0) 2024.08.14
16. Update, Delete 구현하기  (0) 2024.08.14
15. Create, Read 구현하기(DTO)  (0) 2024.08.14