Skills/Java

Java - JDBC Transaction

aoaa 2022. 10. 18. 23:30

1. Transaction과 Lock

 트랜잭션DB 상태를 변화시키기 위해 수행하는 작업의 단위로 이전에 작성한 글에서 용어를 정리했었습니다.

간단하게 정리하자면 DB의 상태를 변화(SQL 질의)시키기 위해 수행하는 작업의 완전성을 위해, 작업을 완벽하게 처리하거나 혹은 처리하지 못할 경우에 원 상태로 복구하여 작업의 일부만 적용되지 않도록 해주는 기능을 말합니다. 

 

 사용자가 DB에 접근하기 위해서는 Spring의 WAS 서버나 DB 접근 툴(H2 console)과 같은 클라이언트를 통해 DB에 접근할 수 있습니다. 이 때, 클라이언트는 DB 서버에 연결을 요청하고 커넥션을 맺게되는데 DB 서버는 내부에 세션이라는 것을 만들어 모든 요청을 세션을 통해 실행하게 됩니다.

 

 한 세션에서 트랜잭션 처리를 하는 동안에 다른 세션에서 트랜잭션을 시도한다면 데이터를 수정하는 동안에 commit, rollback전 까지는 다른 세션에서 해당 데이터를 수정할 수 없도록 막아야 하는데 이를 DB Lock이라고 합니다. 

 

 트랜잭션 처리를 한다는 것은 commit을 수동으로 한다는 의미도 있는데, 이는 sql에서 auto commit이 기본으로 설정되어 있어 쿼리를 실행한 뒤에 DB에 실제 데이터가 반영됩니다. 위에 설명했던 것처럼 작업이 잘못되었을 경우 원 상태로 복구해야하는 상태가 되야하기 때문에 자동 commit이 아닌 수동 commit을 하도록 되는 것입니다. 

 


2. JDBC 응용

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); //트랜잭션 시작

            //비즈니스 로직 수행
            businessLogic(con, fromId, toId, money);
            con.commit(); //성공 시 commit
        } catch (Exception e) {
            con.rollback(); //실패 시 rollback
            throw new IllegalStateException(e);
        } finally {
            release(con);
        }
    }
    
    
    private void release(Connection con) {
        if (con != null) {
            try {
                con.setAutoCommit(true); //커넥션 풀에서 autocmiit true로 유지
                con.close();
            } catch (Exception e) {
                log.info("error", e);
            }
        }

 먼저 datasource를 전달해 Connection을 맺는데 성공하면 세션이 생성이 됩니다.

트랜잭션 처리를 위해 setAutoCommit(false) 메서드를 통해 수동으로 처리되도록 해줍니다.

 이 후 비즈니스 로직(계좌 이체실행)을 수행하게 되는데 트랜잭션이 비즈니스 로직이 있는 Service Layer에서 시작하게 되는데, 이는 비즈니스 로직이 잘못되어 발생하는 문제를 함께 rollback 해야되기 때문입니다. 트랜잭션을 시작하려면 커넥션이 필요한데 Service Layer에서 커넥션을 생성하고 commit 이후 커넥션을 종료해야 합니다. (트랜잭션 사용 중 같은 커넥션 유지)

 예외(오류)가 발생하게 되면 rollback을 발생시키게 되고 finally에서 커넥션을 모두 사용하고 종료해줍니다.(release)

이 때 커넥션 풀을 사용하게 되는 경우 커넥션이 종료되지 않고 커넥션 풀에 반납되기 때문에, 현재 수동커밋(setAutoCommit(false))를 커넥션 풀에 돌려주기 전에 default인 자동 커밋(setAutoCommit(true))로 변경해주는 것이 좋습니다.