들어가며
- 저번 포스트에서 DataSource 인터페이스를 사용하여 커넥션을 얻는 것에 대해 알아보았다.
- 이번 포스트에서는 배운 방식을 레포지토리에 적용하여 어떻게 변경되는지 알아보자.
RepositoryV1 구현
- 커넥션을 얻는 부분에서 많은 변경이 발생된다.
public class MemberRepositoryV1{
private final DataSource dataSource;
public MemberRepositoryV1(DataSource dataSource){
this.dataSource = dataSource;
}
public Member save(Member member) throws SQLException{
...
}
public Member findById(String memberId) throws SQLException{
...
}
public void update(String memberId, int money) throws SQLExceptions{
...
}
public void delete(String memberId, int money) throws SQLExceptions{
...
}
public void close(Connection conn, Statement stmt, ResultSet rs){
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(stmt);
JdbcUtils.closeConnection(conn);
}
private Connection getConnection(){
return dataSource.getConnection();
}
}
- 데이터를 저장, 조회, 수정, 삭제를 하는 부분은 변경이 발생하지 않는다. getConnection()메서드를 통해 커넥션을 얻는 구조이기 때문에 getConnection() 메서드의 내용을 수정해주면 되기 때문이다.
- 보면 dataSource를 DI를 통해 주입받는 것을 확인할 수 있다.
- DI 덕분에 만약 해당 레포지토리를 사용하려 할 때 구현체가 변경되더라도 구현체를 꽂아주는 설정 파일만 수정하면 해당 레포지토리 코드를 수정할 필요가 사라진다.(DI + OCP)
- 만약 스프링을 사용한다고 가정한다면 다음과 같이 구현해주면 된다.
@Repository
@RequiredArgsConstructor
public class MemberRepositoryV1{
private final DataSource dataSource;
public Member save(Member member) throws SQLException{
...
}
public Member findById(String memberId) throws SQLException{
...
}
public void update(String memberId, int money) throws SQLExceptions{
...
}
public void delete(String memberId, int money) throws SQLExceptions{
...
}
public void close(Connection conn, Statement stmt, ResultSet rs){
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(stmt);
JdbcUtils.closeConnection(conn);
}
private Connection getConnection(){
return dataSource.getConnection();
}
}
@Configuration
public class AppConfiguration{
@Bean
public DataSource hikariDataSource(){
return new HikariDataSource();
}
...
}
- 컴포넌트 스캔을 사용한다면 클래스로 만들어 @Component를 통해서도 스프링 프레임워크의 DI 기능을 사용할 수 있을 것이다.
- close() 메서드를 유심히 보자 JdbcUtils라는 객체를 통해 연결을 닫는데 사용되는 많은 코드들을 매우 짧게 줄일 수 있었다. JdbcUtils 클래스는 JDBC를 편리하게 다룰 수 있도록 여러 편의 메서드를 제공하는데 그것들을 사용한 것이다.
레포지토리 테스트
class MemberRepositoryV0Test{
MemberRepositoryV1 memberRepository;
@BeforeEach
void beforeEach() throws Exception{
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
memberRepository = new MemberRepositoryV1(dataSource);
Thread.sleep(1000);
}
@Test
void crud() throws SQLException{
Member member = new Member("memberA", 10000);
repository.save(member);
Member memberA = repository.findById("memberA");
Assertions.assertThat(memberA).isEqualTo(member);
repository.update(member.getMemberId(), 12000);
memberA = repository.findById("memberA");
Assertions.assertThat(memberA).isEqualTo(member);
Assertions.assertThat(memberA.getMoney()).isEqualTo(12000);
repository.delete("memberA");
Assertions.assertThatThrownBy(() -> repository.findById("memberA"))
.isInstanceOf(NoSuchElementException.class);
}
}
- @BeforeEach 어노테이션은 테스트 프레임워크에서 테스트를 수행하기 전에 수행되는 메서드임을 뜻한다. 즉 crud 메서드가 실행되기 전에 HikariDataSource객체가 생성되고, 초기화된 뒤 memberRepository로 주입이 수행된다.
- 로그를 사용하여 확인해보면 커넥션 풀을 사용하여 데이터를 삽입, 조회, 수정, 삭제를 하고 있음을 알 수 있다. 다만 현재는 요청이 동시다발적으로 들어오지 않아 하나의 커넥션만 사용되고 있음을 유의해야 한다.
'Spring & JPA > JDBC' 카테고리의 다른 글
JDBC - JDBC 커넥션 풀 - DataSource (0) | 2023.06.05 |
---|---|
JDBC - JDBC 커넥션 풀 - 커넥션 풀의 개념 (0) | 2023.06.05 |
JDBC - JDBC 사용 - 3. 데이터 수정과 삭제 (0) | 2023.06.03 |
JDBC - JDBC 사용 - 2. 데이터 조회 (0) | 2023.06.03 |
JDBC - JDBC사용 - 1. 데이터 저장 (0) | 2023.06.03 |