LUMI_dev

JDBC란? 본문

등장배경

더보기

서버는 데이터베이스와 어떠한 방법을 통해 소통을 할까?

 

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

  1. 우선 DB에 연결하기 위해 커넥션 연결
  2. SQL을 작성한 후 커넥션을 통해 SQL을 요청
  3. 요청한 SQL에 대한 결과를 응답 받음 

 

그러나 이 경우 기존에 사용하던 MySQL 서버를 PostgreSQL 서버로 변경해야 하는 상황에서

커넥션을 연결하는 방법, SQL을 전달하는 방법, 결과를 응답받는 방법 모두 달라질 수 있음 

 

그래서 등장한 것이 JDBC 표준 인터페이스

 

JDBC (Java Database Connectivity) - DB 교체 간편하게

: DB에 접근할 수 있도록 Java에서 제공하는 API

 

JDBC Template  - DB 연결 간편하게 (사용할 일은 희박)

커넥션 연결, statement 준비 및 실행, 커넥션 종료 등의 반복적이고 중복되는 작업들을 대신 처리


JDBC Template 사용방법

1 application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/memo
spring.datasource.username=root
spring.datasource.password={비밀번호}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

 

2. build.gradle : JDBC 라이브러리, MySQL 추가

// MySQL
implementation 'mysql:mysql-connector-java:8.0.28'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'

 

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

private final JdbcTemplate jdbctemplate;

public MemoRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
}

생성자의 파라메터를 통해 JdbcTemplate 객체가 자동으로 넘어와 jdbctemplate 변수에 저장됨 


실습) 

MemoController

package com.sparta.sparta_memo_project.Controller;

import com.sparta.sparta_memo_project.dto.MemoRequestDto;
import com.sparta.sparta_memo_project.dto.MemoResponseDto;
import com.sparta.sparta_memo_project.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로 만들기  - Entity (테이블의 한 행에 해당되는 데이터)
        Memo memo = new Memo(requestDto);

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

        String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
        
        //여기에서의 update는 insert,delete,update를 처리하는 JdbcTemplate update 메소드 
        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() { //MemoDto가 하나 생성되면서 List 타입으로 묶여서 반환
        // 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 타입으로 변환해줄 메서드
                
                //get~ 부분은 각 column의 데이터 타입
                Long id = rs.getLong("id");
                String username = rs.getString("username");
                String contents = rs.getString("contents");
                
                //위 코드로 MemoResponseDto가 하나 만들어짐
                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);
    }
}

 

MemoResponseDto

package com.sparta.sparta_memo_project.dto;

import lombok.Getter;
import com.sparta.sparta_memo_project.entity.Memo;
@Getter
public class MemoResponseDto {
    private Long id;
    private String username;
    private String contents;

    public MemoResponseDto(Memo memo) {
        this.id = memo.getId();
        this.username = memo.getUsername();
        this.contents = memo.getContents();
    }

    public MemoResponseDto(Long id, String username, String contents) {
        this.id = id;
        this.username = username;
        this.contents = contents;
    }
}

 


column 하나 = java 객체의 field 하나

테이블의 한 row = java 객체 하나