์์ 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 ์คํ์ ์ฑ๊ณตํ๋ค.
๋ด์ฉ ๋ฐ ์ด๋ฏธ์ง ์ถ์ฒ : ๊น์ํ์ ์คํ๋ง ์ ๋ฌธ