관련 내용
<JDBC, Spring - Transaction 처리에 대한 완벽한 이해>
- (현재 글)순수 JDBC만을 사용한 Transaction 사용 방법 알아보기
- 순수 JDBC-Transaction 문제 Spring TransactionManger로 해결하기 - 트랜잭션 템플릿, 트랜잭션 AOP 사용
JDBC Trasaction문제 Spring으로 해결하기
- Spring Transaction AOP 동작 과정과 주의 사항 알아보기
스프링 Trasaction AOP 동작 과정과 주의 사항
- Spring Transaction 전파 원리 이해하기
- Spring을 사용한 JDBC 예외 누수 문제 해결하기
Spring을 사용한 JDBC 예외 누수 문제 해결하기
- 자바 예외에 대한 이해
개요와 목적
이번 시간에는 Java의 JDBC 기술에서 단순히 DB만 사용하는 것이 아니라, 트랜잭션 처리를 하는 방법에 대해서 알아본다.
트랜잭션과 DB Lcok에 대한 이론적 이해는 아래 블로그 글에서 확인할 수 있다.
[백엔드/DB 지식] - Transaction과 ACID 쉽게 이해하기(+MySQL transaction 설정 방법)
[백엔드/DB 지식] - DB Lock에 대한 이해와 MySQL Lock의 특징
JDBC에서 Transaction 사용의 핵심
- 동일한 커넥션(세션)을 유지하기 위해서, 서비스 메소드 내에서 커넥션을 획득한다.
- con.setAutoCommit(false)으로 트랜잭션을 시작한다.
- 모든 SQL을 실행하는 Repository 메소드에 동일한 커넥션을 파라미터로 전달한다.
- 성공 시 con.commit()을 한다.
- 실패 시 con.rollback()을 한다.
- 마지막 서비스 계층에서 con.close()를 통해 커넥션을 종료한다.
코드를 통해 JDBC Transaction 처리 알아보기
transaction이 필요한 상황 가정하기
memberA와 memberEx는 각각 돈 10000원을 가지고 있다. memberA가 memberEx에게 2000원을 보내는 상황이다. 그런데 시스템 상 문제가 발생하여 해당 처리가 롤백되어야한다. 트랜잭션이 제대로 작동한다면, memberA와 memberEx 돈이 10000원이 그대로 남아있어야 한다.
transaction을 사용하려면 하나의 세션, 커넥션 안에서 이루어져야 한다.
트랜잭션을 적용하려면 하나의 세션을 유지해야 한다. 하나의 세션을 유지하려면 동일한 커넥션을 사용해서 SQL 쿼리를 보내야 한다. 결국 레포지토리 계층이 아니라, 서비스 계층에서 커넥션을 만들고, 트랜잭션 커밋 이후에 커넥션을 종료해야 한다.
<Connection을 파라미터로 받는 방식으로 변경 - 서비스 계층에서 동일한 커넥션으로 SQL 요청을 날리기 위해서>
KIMHWANG\jdbc\src\main\java\hello\jdbc\repository\MemberRepositoryV1.java
→
KIMHWANG\jdbc\src\main\java\hello\jdbc\repository\MemberRepositoryV2.java
//MemberRepositoryV1.java
public void update(String memberId, int money) throws SQLException {
String sql = "update member set money=? where member_id=?";
Connection con = null;
PreparedStatement pstmt = null;
try {
//메소드 내에서 새로운 connection을 획득한다.
//이러면 서비스 코드 내에서 동일한 connection을 유지할 수 없다.
con = getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, money);
pstmt.setString(2, memberId);
int resultSize = pstmt.executeUpdate();
log.info("resultSize={}", resultSize);
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
//->
//MemberRepositoryV2.java
//동일한 connection을 유지하기 위해서 파라미터로 connection을 받는다.
public void update(Connection con, String memberId, int money) throws
SQLException {
String sql = "update member set money=? where member_id=?";
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, money);
pstmt.setString(2, memberId);
pstmt.executeUpdate();
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
//connection은 여기서 닫지 않는다. 서비스 계층에서 한번에 닫는다.
JdbcUtils.closeStatement(pstmt);
}
}
transaction이 동작하는 계좌 이체 서비스 코드
트랜잭션이 적용되지 않은 서비스 코드는 깃허브 MemberServiceV0.java에서 볼 수 있다.
KIMHWANG\jdbc\src\main\java\hello\jdbc\service\MemberServiceV2.java
public class MemberServiceV2 {
private final DataSource dataSource;
private final MemberRepositoryV2 memberRepository;
public void accountTransfer(String fromId, String toId, int money) throws
SQLException {
//동일한 connection을 사용하기 위해서 서비스 코드 내부에서 connection 획득
//repository에 해당 connection 동일하게 전달
Connection con = dataSource.getConnection();
try {
//setAutoCommit(false)로 트랜잭션 시작
con.setAutoCommit(false);
//계좌 이체 비지니스 로직
Member fromMember = memberRepository.findById(con, fromId);
Member toMember = memberRepository.findById(con, toId);
memberRepository.update(con, fromId, fromMember.getMoney() - money);
//에러 발생 상황 연출
if (toMember.getMemberId().equals("ex")) {
throw new IllegalStateException("이체중 예외 발생");
}
memberRepository.update(con, toId, toMember.getMoney() + money);
//성공시 커밋
con.commit();
} catch (Exception e) {
//에러발생 - 실패시 롤백
con.rollback();
throw new IllegalStateException(e);
} finally {
//서비스 계층에서 connection 종료
release(con);
}
}
private void release(Connection con) {
if (con != null) {
try {
//커넥션 풀 고려
con.setAutoCommit(true);
con.close();
} catch (Exception e) {
log.info("error", e);
}
}
}
}
'Web Sever 개발과 CS 기초 > 스프링' 카테고리의 다른 글
스프링 Trasaction AOP 동작 과정과 주의 사항 (0) | 2023.04.26 |
---|---|
JDBC Trasaction문제 Spring으로 해결하기 (0) | 2023.04.26 |
ConnectionPool에 대한 이해와 DataSource 인터페이스로 커넥션을 획득하는 방법 통일하기 (0) | 2023.04.13 |
JDBC와 SQL 쿼리를 사용한, Spring DB CRUD 기능 만들기 (0) | 2023.04.13 |
스프링 DB 사용을 위한 JDBC에 대한 이해와 사용 방법 (0) | 2023.04.13 |