JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API이다. JDBC는 데이터베이스에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다.

자바는 이렇게 표준 인터페이스를 정의해두었다. 이제부터 개발자는 이 표준 인터페이스만 사용해서 개발하면 된다. 그런데 인터페이스만 있다고해서 기능이 동작하지는 않는다. 이 JDBC 인터페이스를 각각의 DB 회사에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하는데, 이것을 JDBC 드라이버라 한다.



DriverManager : JDBC가 제공하며 라이브러리에 등록된 DB 드라이버들을 관리하고, 커넥션을 획득하는 기능을 제공한다.



@Test
void dataSourceDriverManager() throws SQLException {
//DriverManagerDataSource - 항상 새로운 커넥션 획득
DriverManagerDataSource dataSource =
new DriverManagerDataSource(URL, USERNAME, PASSWORD);
useDataSource(dataSource);
}
@Test
void dataSourceConnectionPool() throws SQLException,
InterruptedException {
//커넥션 풀링: HikariProxyConnection(Proxy) -> JdbcConnection(Target)
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10);
dataSource.setPoolName("MyPool"); //커넥션 풀 최대 사이즈
useDataSource(dataSource);
Thread.sleep(1000); //커넥션 풀에서 커넥션 생성 시간 대기
}
설정과 사용의 분리

set autocommit false; //트랜잭션 시작


@Slf4j
@RequiredArgsConstructor
public class MemberServiceV2 {
private final DataSource dataSource;
private final MemberRepositoryV2 memberRepository;
public void accountTransfer(String fromId, String toId, int money) throws SQLException {
Connection con = dataSource.getConnection();
try {
con.setAutoCommit(false); //트랜잭션 시작
//비즈니스 로직
bizLogic(con, fromId, toId, money);
con.commit(); //성공시 커밋
} catch (Exception e) {
con.rollback(); //실패시 롤백
throw new IllegalStateException(e);
} finally {
release(con);
}
}
private void bizLogic(Connection con, String fromId, String toId, int money)
throws SQLException {
Member fromMember = memberRepository.findById(con, fromId);
Member toMember = memberRepository.findById(con, toId);
memberRepository.update(con, fromId, fromMember.getMoney() - money);
memberRepository.update(con, toId, toMember.getMoney() + money);
}
}

PlatformTransactionManager 으로 해결
package org.springframework.transaction;
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}

트랜잭션 동기화 매니저

트랜잭션 템플릿으로 해결
public class TransactionTemplate {
private PlatformTransactionManager transactionManager;
public <T> T execute(TransactionCallback<T> action){..}
void executeWithoutResult(Consumer<TransactionStatus> action){..}
}
@Transactional(트랜잭션 AOP) 애노테이션으로 해결

@Transactional
public void accountTransfer(String fromId, String toId, int money)
throws SQLException {
bizLogic(fromId, toId, money);
}
DataSource 스프링에서 기본으로 사용할 데이터소스를 스프링 빈으로 등록한다. 추가로 트랜잭션 매니저에서도 사용한다.
DataSourceTransactionManager 트랜잭션 매니저를 스프링 빈으로 등록한다.
스프링 부트의 자동 리소스 등록
스프링 부트는 DataSource와 PlatformTransactionManager을 자동으로 스프링 빈에 등록한다.




SQLExceptionTranslator exTranslator = new
SQLErrorCodeSQLExceptionTranslator(dataSource);
DataAccessException resultEx = exTranslator.translate("select", sql, e);
@Slf4j
public class MemberRepositoryV5 implements MemberRepository {
private final JdbcTemplate template;
public MemberRepositoryV5(DataSource dataSource) {
template = new JdbcTemplate(dataSource);
}
@Override
public Member save(Member member) {
String sql = "insert into member(member_id, money) values(?, ?)";
template.update(sql, member.getMemberId(), member.getMoney());
return member;
}
@Override
public Member findById(String memberId) {
String sql = "select * from member where member_id = ?";
return template.queryForObject(sql, memberRowMapper(), memberId);
}
@Override
public void update(String memberId, int money) {
String sql = "update member set money=? where member_id=?";
template.update(sql, money, memberId);
}
@Override
public void delete(String memberId) {
String sql = "delete from member where member_id=?";
template.update(sql, memberId);
}
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setMemberId(rs.getString("member_id"));
member.setMoney(rs.getInt("money"));
return member;
};
}
JdbcTemplate는 JDBC로 개발할 때 발생하는 반복을 대부분 해결해준다. 그 뿐만 아니라 지금까지 학습했던, 트랜잭션을 위한 커넥션 동기화는 물론이고 예외 발생 시 스프링 예외 변환기도 자동으로 실행해준다.