JDBC - 트랜잭션

트랜잭션 관리의 예는 계좌이체가 가장 좋은 예제이다.
A 계좌에서 B 계좌로 1000 원을 이체한다면 아래와 같다.

과정 1. A계좌에서 1000원을 뺀다.
과정 2. B계좌에서 1000원을 더한다.

계좌이체의 트랜잭션을 관리한다면, 과정 1이 성공하고 과정 2가 실패하면 과정 1까지 취소하여, 과정 1 직전 상태로 복구해야 한다.

트랜잭션 관리를 위해서 과정 1과정 2는 하나의 단위로 봐야 한다.
이때 과정 1과정 2를 묶어서 트랜잭션의 단위라고 한다.

JDBC 프로그램에서 얻은 커넥션은 기본적으로 자동 커밋 모드이다.
자동 커밋 모드는 SQL 문장 하나 하나를 트랜잭션 단위로 본다.
JDBC 트랙잭션 관리 코딩은 자동 커밋 모드를 false로 설정하고 프로그램상으로 커밋 시점을 정의한다.

계좌이체에 적용하면 다음과 같다.

con.setAutoCommit(false);
과정 1. A계좌에서 1000원을 뺀다.
과정 2. B계좌에서 1000원을 더한다.
con.commit();

트랜잭션 예제를 위해서 아래와 같이 scott계정에 ACCOUNT 테이블을 만들고 데이터를 인서트한다.

create table account (
 accountno varchar2(3) primary key,
 balance number,
 constraint account_balance_ck check(balance between 0 and 3000)
)
/
insert into account values ('111', 3000)
/
insert into account values ('222', 2000)
/

TransactionPairs.java의 메인 메소드에 아래 SQL 문을 JDBC로 실행하는 코드를 작성한다.

update account set balance = balance - 1500 where accountno = '111'
update account set balance = balance + 1500 where accountno = '222'

JDBC 코드는 아래 순서를 참조한다.

  1. JDBC 드라이버 로딩
  2. Connection 맺기
  3. SQL 실행
  4. [SQL문이 select문이었다면 ResultSet을 이용한 처리]
  5. 자원 반환
TransactionPairs.java
package net.java_school.jdbc.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TransactionPairs {
	static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
	static final String USER = "scott";
	static final String PASS = "tiger";
	
	public static void main(String[] args) {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		Connection con = null;
		PreparedStatement pstmt = null;
		String sql = "UPDATE account SET balance = balance + ? WHERE accountno = ?";
		
		try {
			con = DriverManager.getConnection(URL, USER, PASS);
			
			con.setAutoCommit(false);
			
			pstmt = con.prepareStatement(sql);
			
			pstmt.setInt(1, -1500);
			pstmt.setString(2, "111");
			pstmt.executeUpdate();
			
			pstmt.setInt(1, 1500);
			pstmt.setString(2, "222");
			pstmt.executeUpdate();
			
			con.commit();
			
		} catch (SQLException e) {
			e.printStackTrace();
			try {
				con.rollback(); //익셉션이 발생하면 롤백한다.
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

실행하고 SQL*PLUS로 결과를 확인한다.
java.sql.SQLException: ORA-02290: 체크 제약조건(SCOTT.ACCOUNT_BALANCE_CK)이 위배되었습니다 라는 익셉션 메시지를 보게 된다.
ACCOUNT 테이블의 BALANCE 컬럼은 0에서 3000까지의 수만 저장될 수 있기 때문이다.
그 결과 catch블록에서 롤백이 실행된다.