YOONJI
article thumbnail

์ˆœ์ˆ˜ JDBC

 

ํ™˜๊ฒฝ ์„ค์ •

# build.gradle ํŒŒ์ผ์— jdbc, h2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€

// DB์™€ ์—ฐ๋™ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋“œ๋ผ์ด๋ฒ„
implementation 'org.springframework.boot:spring-boot-starter-jdbc'

// DB์™€ ๋ถ™์„ ๋•Œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ
runtimeOnly 'com.h2database:h2'

 

# ์Šคํ”„๋ง ๋ถ€ํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ค์ • ์ถ”๊ฐ€

resources/application.properties

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

 

์ฃผ์˜! ์Šคํ”„๋ง๋ถ€ํŠธ 2.4๋ถ€ํ„ฐ๋Š” spring.datasource.username=sa ๋ฅผ ๊ผญ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด Wrong user name or password ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ฐธ๊ณ ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งˆ์ง€๋ง‰์— ๊ณต๋ฐฑ์ด ๋“ค์–ด๊ฐ€๋ฉด ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. spring.datasource.username=sa ๊ณต๋ฐฑ ์ฃผ์˜, ๊ณต๋ฐฑ์€ ๋ชจ๋‘ ์ œ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.

 

 

JDBC ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„

์ฃผ์˜! ์ด๋ ‡๊ฒŒ JDBC API๋กœ ์ง์ ‘ ์ฝ”๋”ฉํ•˜๋Š” ๊ฒƒ์€ 20๋…„ ์ „ ์ด์•ผ๊ธฐ์ด๋‹ค.
๋”ฐ๋ผ์„œ ๊ณ ๋Œ€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ด๋ ‡๊ฒŒ ๊ณ ์ƒํ•˜๊ณ  ์‚ด์•˜๊ตฌ๋‚˜ ์ƒ๊ฐํ•˜๊ณ , ์ •์‹ ๊ฑด๊ฐ•์„ ์œ„ํ•ด ์ฐธ๊ณ ๋งŒ ํ•˜๊ณ  ๋„˜์–ด๊ฐ€์ž.

 

ํšŒ์›์„ ์ €์žฅํ•˜๋Š” '์—ญํ• '์€ MemberRepository๊ฐ€ ํ•˜์ง€๋งŒ, '๊ตฌํ˜„'์„ ๋ฉ”๋ชจ๋ฆฌ์— ํ•  ๊ฒƒ์ธ์ง€ DB์™€ ์—ฐ๋™ํ•ด์„œ ํ•  ๊ฒƒ์ธ์ง€์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

 

# Jdbc ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ
src/main/java/hello.hellospring/repository/JdbcMemberRepository.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.jdbc.datasource.DataSourceUtils;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class JdbcMemberRepository implements MemberRepository {

    private final DataSource dataSource;

    public JdbcMemberRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Member save(Member member) {
        String sql = "insert into member(name) values(?)";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        /*
            getConnection์„ ํ†ตํ•ด ์ปค๋„ฅ์…˜์„ ๊ฐ€์ ธ์˜ด
            prepareStatement์— sql ์ ์–ด์ฃผ๊ณ  RETURN_GENERATED_KEYS๋ผ๋Š” ํŠน๋ณ„ ์˜ต์…˜์„ ์คŒ
            ์ด ์˜ต์…˜์€ ์šฐ๋ฆฌ๊ฐ€ DB์— insert ํ•ด์•ผ๋งŒ ์•Œ ์ˆ˜ ์žˆ๋Š” id ๊ฐ’์„ ์–ป์„ ๋•Œ ์‚ฌ์šฉํ•จ
            setString์—์„œ parameterIndex์— 1์„ ๋„ฃ์–ด์ฃผ๋ฉด ์œ„ String sql์˜ ๋ฌผ์Œํ‘œ(?)์™€ ๋งค์นญ
            ๋ฌผ์Œํ‘œ์— member.getName()์œผ๋กœ ๊ฐ’์„ ๋„ฃ์–ด์คŒ
            executeUpdate ํ•˜๋ฉด DB์— ์‹ค์ œ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ
            getGeneratedKeys๋ฅผ ํ†ตํ•ด ๋ฐฉ๊ธˆ ์ƒ์„ฑ๋œ ํ‚ค์˜ id๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์คŒ

            ๋งŒ์•ฝ rs ๋‹ค์Œ ๊ฐ’์ด ์žˆ๋‹ค๋ฉด getLong์„ ํ†ตํ•ด ๊ฐ’์„ ๊บผ๋‚ด์„œ ์„ธํŒ…ํ•ด ์คŒ
            ์—†๋‹ค๋ฉด ์‹คํŒจ ๋ฌธ๊ตฌ ๋˜์ ธ ์คŒ

            ์ดํ›„ ์˜ˆ์™ธ์ฒ˜๋ฆฌ ํ•ด์ฃผ๊ธฐ
        */

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql,
                    Statement.RETURN_GENERATED_KEYS);

            pstmt.setString(1, member.getName());

            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();

            if (rs.next()) {
                member.setId(rs.getLong(1));
            } else {
                throw new SQLException("id ์กฐํšŒ ์‹คํŒจ");
            }
            return member;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

    @Override
    public Optional<Member> findById(Long id) {
        String sql = "select * from member where id = ?";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        /*
            ์œ„์™€ ๋น„์Šทํ•œ ๋ฐฉ์‹
            executeQuery๋ฅผ ํ†ตํ•ด result ๊ฐ’์„ ๋ฐ›์•„์˜ด
            ๋ฉค๋ฒ„๊ฐ€ ์žˆ์œผ๋ฉด ์ญ‰ ๋งŒ๋“ค๊ณ  ๋ฐ˜ํ™˜
        */

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.setLong(1, id);

            rs = pstmt.executeQuery();

            if(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return Optional.of(member);
            } else {
                return Optional.empty();
            }

        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

    @Override
    public List<Member> findAll() {
        String sql = "select * from member";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        /*
            ์œ„์™€ ๋น„์Šทํ•œ ๋ฐฉ์‹
            ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ, ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฃจํ”„ ๋Œ๋ฉด์„œ add๋ฅผ ํ†ตํ•ด ๋ฉค๋ฒ„ ๋‹ด์€ ํ›„ ๋ฐ˜ํ™˜
        */

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);

            rs = pstmt.executeQuery();

            List<Member> members = new ArrayList<>();
            while(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                members.add(member);
            }

            return members;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

    @Override
    public Optional<Member> findByName(String name) {
        String sql = "select * from member where name = ?";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, name);
            rs = pstmt.executeQuery();
            if(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return Optional.of(member);
            }

            return Optional.empty();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

    private Connection getConnection() {
        // DataSourceUtils๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด DB ํŠธ๋žœ์žญ์…˜์— ๊ฑธ๋ ธ์„ ๋•Œ DB ์ปค๋„ฅ์…˜์„ ๋˜‘๊ฐ™์ด ์œ ์ง€์‹œ์ผœ ์คŒ
        return DataSourceUtils.getConnection(dataSource);
    }

    private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
    {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } try {
            if (pstmt != null) {
                pstmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) {
                close(conn);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void close(Connection conn) throws SQLException {
        DataSourceUtils.releaseConnection(conn, dataSource);
    }
}

 

 

# ์Šคํ”„๋ง ์„ค์ • ๋ณ€๊ฒฝ

src/main/java/hello.hellospring/SpringConfig.java

package hello.hellospring;

import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class SpringConfig {

    private DataSource dataSource;

    @Autowired
    public SpringConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        // return new MemoryMemberRepository();
        return new JdbcMemberRepository(dataSource);
    }
}

> DataSource๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์„ ํš๋“ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋‹ค.
   ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ DataSource๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋งŒ๋“ค์–ด๋‘”๋‹ค.
   ๊ทธ๋ž˜์„œ DI๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ฒฐ๊ณผ

(ํ„ฐ๋ฏธ๋„์—์„œ h2.sh๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์žˆ์–ด์•ผ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•จ์— ์ฃผ์˜)

์šฐ๋ฆฌ๊ฐ€ DB์— ์ž…๋ ฅํ–ˆ๋˜ spring, spring2๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค.

 

์ด๋ฒˆ์—๋Š” ํšŒ์› ๊ฐ€์ž… ํŽ˜์ด์ง€์—์„œ ์ด๋ฆ„์ด jpa์ธ ํšŒ์›์„ ๋“ฑ๋กํ•ด๋ณด์ž.

 

๋“ฑ๋ก ์„ฑ๊ณต. DB์™€ ์ž˜ ์—ฐ๊ฒฐ๋œ ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

 

 

๊ตฌํ˜„ ํด๋ž˜์Šค ์ถ”๊ฐ€ ์ด๋ฏธ์ง€

MemberService๊ฐ€ MemberRepository์— ์˜์กดํ•˜๊ณ  ์žˆ๋‹ค.

MemberRepository๋Š” ๊ตฌํ˜„์ฒด๋กœ MemoryMemberRepository์™€ JdbcMemberRepository๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ.

 

 

์Šคํ”„๋ง ์„ค์ • ์ด๋ฏธ์ง€

์Šคํ”„๋ง ๋นˆ์—์„œ MemoryMemberRepository๋ฅผ ๋นผ๊ณ  JdbcMemberRepository๋กœ ๋“ฑ๋กํ•ด์ฃผ์—ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ตฌํ˜„์ฒด๊ฐ€ ๋ฐ”๋€Œ์–ด JdbcMemberRepository๋กœ ๋Œ์•„๊ฐ€๊ฒŒ ๋œ๋‹ค.

 


๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™(OCP, Open-Closed Principle) ; ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •/๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค.

> ์œ„์ฒ˜๋Ÿผ ๊ฐ์ฒด์ง€ํ–ฅ์—์„œ์˜ ๋‹คํ˜•์„ฑ์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

> ์Šคํ”„๋ง์˜ DI(Dependencies Injection)์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ์†๋Œ€์ง€ ์•Š๊ณ , ์„ค์ •๋งŒ์œผ๋กœ ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

> ๋ฐ์ดํ„ฐ๋ฅผ DB์— ์ €์žฅํ•˜๋ฏ€๋กœ ์Šคํ”„๋ง ์„œ๋ฒ„๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅ๋œ๋‹ค.

 

 

์Šคํ”„๋ง์„ ์™œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ์„ค๊ณ„๊ฐ€ ์ข‹์€ ์ด์œ ๋Š” ๋‹คํ˜•์„ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

(ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‘๊ณ  ๊ตฌํ˜„์ฒด๋ฅผ ๋ฐ”๊ฟ” ๋ผ์šฐ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅ)

๋˜ํ•œ, Dependency Injection ๋•๋ถ„์— ๊ธฐ์กด ์ฝ”๋“œ๋Š” ํ•˜๋‚˜๋„ ์†๋Œ€์ง€ ์•Š๊ณ 

์˜ค์ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ(assembly)๋งŒ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

์ด ๊ธฐ๋Šฅ๋“ค์„ ๊ต‰์žฅํžˆ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋˜๋„๋ก ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ง€์›ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์Šคํ”„๋ง์˜ ์žฅ์ !


์Šคํ”„๋ง ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

์ด์ œ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ DB๊นŒ์ง€ ์—ฐ๊ฒฐํ•œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์ž.

 

 

ํšŒ์› ์„œ๋น„์Šค ์Šคํ”„๋ง ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

src/test/java/hello.hellospring/service/MemberServiceIntegrationTest.java

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;

    @Test
    void ํšŒ์›๊ฐ€์ž…() {
        //given
        Member member = new Member();
        member.setName("hello");

        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    public void ์ค‘๋ณต_ํšŒ์›_์˜ˆ์™ธ() {
        //given
        Member member1 = new Member();
        member1.setName("spring");

        Member member2 = new Member();
        member2.setName("spring");

        //when
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
        assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
    }
}

 

 

๊ฒฐ๊ณผ

์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•œ ๋’ค ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž…๋ ฅํ–ˆ๋˜ spring์ด๋ผ๋Š” ํšŒ์›์ด ์ด๋ฏธ DB์— ์กด์žฌํ•˜๋Š”๋ฐ

ํ…Œ์ŠคํŠธ์—์„œ spring์ด๋ผ๋Š” ์ด๋ฆ„์˜ ํšŒ์›์„ ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ delete from member๋ฅผ ํ†ตํ•ด DB์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ง€์›Œ์ฃผ๋ฉด ์ •์ƒ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

(๋ณดํ†ต ํ…Œ์ŠคํŠธ ์ „์šฉ DB๋ฅผ ๊ตฌ์ถ•ํ•˜๊ฑฐ๋‚˜ ๋กœ์ปฌ PC์˜ DB์—์„œ ํ…Œ์ŠคํŠธ ํ•จ)

 

ํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ๋ฒˆ ๋” ์‹คํ–‰ํ•˜๋ฉด DB ์ค‘๋ณต ๋ฐ์ดํ„ฐ๋กœ ์ธํ•ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

์ด๋Ÿด ๋•Œ @AfterEach๋ณด๋‹ค๋Š” @Transactional์„ ์‚ฌ์šฉํ•˜๋ฉด ์ข€ ๋” ํŽธ๋ฆฌํ•˜๋‹ค.

 

@SpringBootTest : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•จ๊ป˜ ์‹คํ–‰ํ•œ๋‹ค.

@Transactional : ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ์ด ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ์œผ๋ฉด, ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , ํ…Œ์ŠคํŠธ ์™„๋ฃŒ ํ›„์— ํ•ญ์ƒ ๋กค๋ฐฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด DB์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค์Œ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

(์„œ๋น„์Šค์—์„œ๋Š” ๋กค๋ฐฑ X, ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์—์„œ๋งŒ ๋กค๋ฐฑ)

 

@Transactional์„ ํ†ตํ•œ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ›„ DB์— ์ ‘์†ํ•ด๋ณด๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ํ•ด๋„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

** DB๊นŒ์ง€ ์˜ฌ๋ฆฌ๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ณด๋‹ค๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณดํ†ต ์ข‹์€ ํ…Œ์ŠคํŠธ์ด๋ฏ€๋กœ ์ชผ๊ฐœ์„œ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์ž!

 


์Šคํ”„๋ง JDBC Template

์ˆœ์ˆ˜ Jdbc์™€ ๋™์ผํ•œ ํ™˜๊ฒฝ์„ค์ •์„ ํ•˜๋ฉด ๋œ๋‹ค.

์Šคํ”„๋ง JdbcTemplate๊ณผ MyBatis ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” JDBC API์—์„œ ๋ณธ ๋ฐ˜๋ณต ์ฝ”๋“œ๋ฅผ ๋Œ€๋ถ€๋ถ„ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

ํ•˜์ง€๋งŒ SQL์€ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

 

์Šคํ”„๋ง JdbcTemplate ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„

 

# ์Šคํ”„๋ง JdbcTemplate ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ

src/main/java/hello.hellospring/repository/JdbcTemplateMemberRepository.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class JdbcTemplateMemberRepository implements MemberRepository{

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public Member save(Member member) {
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");

        Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", member.getName());

        Number key = jdbcInsert.executeAndReturnKey(new
                MapSqlParameterSource(parameters));
        member.setId(key.longValue());
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    }

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }

    private RowMapper<Member> memberRowMapper() {
        return (rs, rowNum) -> {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }
}

 

# JdbcTemplate์„ ์‚ฌ์šฉํ•˜๋„๋ก ์Šคํ”„๋ง ์„ค์ • ๋ณ€๊ฒฝ

src/main/java/hello.hellospring/SpringConfig.java

package hello.hellospring;

import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.repository.JdbcTemplateMemberRepository;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class SpringConfig {

    private DataSource dataSource;

    @Autowired
    public SpringConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public MemberService memberService() {
        // ์Šคํ”„๋ง ๋นˆ์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” memberRepository๋ฅผ memberService์— ๋„ฃ์–ด์คŒ
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        // return new MemoryMemberRepository();
        // return new JdbcMemberRepository(dataSource);
        return new JdbcTemplateMemberRepository(dataSource);
    }
}

 

 

๊ฒฐ๊ณผ

JdbcTemplateMemberRepository ์‹คํ–‰์— ์„ฑ๊ณตํ–ˆ๋‹ค.

 

 

 

 

๋‚ด์šฉ ๋ฐ ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ : ๊น€์˜ํ•œ์˜ ์Šคํ”„๋ง ์ž…๋ฌธ    

profile

YOONJI

@๊ธฐ๋ฎจ์ง€

ํฌ์ŠคํŒ…์ด ์ข‹์•˜๋‹ค๋ฉด "์ข‹์•„์š”โค๏ธ" ๋˜๋Š” "๊ตฌ๋…๐Ÿ‘๐Ÿป" ํ•ด์ฃผ์„ธ์š”!