- JDBC 52022년 07월 13일
- starryeye
- 작성자
- 2022.07.13.:46
트랜잭션
여러개의 SQL 쿼리를 하나의 묶음 단위로 관리하겠다는 의미이다.
예를 들면, 돈을 이체 할때 A계좌에서는 돈이 빠져나가야 하며
B계좌에서는 돈이 들어와야한다.
-> 다양한 원인의 장애로 인해 B계좌에서 돈이 들어오는 것은 수행되지 않으면 큰일이다.
-> 따라서 하나의 묶음 단위로 성공 혹은 실패를 처리하겠다는 개념이다.
트랜잭션 ACID
4가지..
1. 원자성(Atomicity)
하나의 트랜잭션 내에서 실행한 모든 작업은 모두 성공하거나 모두 실패하거나 둘 중 하나다.
2. 일관성(Consistency)
DB 무결성 제약 조건을 항상 만족
3. 격리성(Isolation)
트랜잭션들은 서로 영향이 없어야 한다.
-> lock 개념
4. 지속성(Durability)
트랜잭션이 성공하면 DB가 업데이트되어야 하며,
트랜잭션이 실패하면 DB가 롤백되어야한다.
트랜잭션간 격리성 보장...
격리성을 완전히 보장하려면 데이터 처리 성능이 매우 나빠진다.
(요청 순서대로 처리해야 하기 때문..)
격리성 보장 수준에 따른 정책(ANSI 표준)
아래로 갈 수록 격리 수준이 높아진다.
(처리 속도가 느려지지만 격리성이 높기 때문에 데이터 신뢰도는 올라감)
1. Read Uncommited
2. Read Committed
3. Repeatable Read
4. Serializable
실무에서는 보통 2, 3번 정도로 사용한다.
트랜잭션 동작과정
1. 클라이언트(애플리케이션)에서 DB로 커넥션을 획득하면 DB내부에서 커넥션 한개당 세션이 하나 만들어진다.
2. 세션이 결국 트랜잭션을 시작
3. 세션은 락을 획득한다. (DB Table의 row)
4. 세션은 SQL을 수행한다.
5. 성공여부에 따라 커밋 혹은 롤백을 수행한다.
6. 트랜잭션을 종료한다. (락도 반납)
(모든 과정이 처리 되는 동안, 동일한 커넥션 및 세션으로 계속 유지 되어야한다.)
7. 이후 커넥션은 쓰레드 풀에 반환되거나.. 종료 될 것이다.
"트랜잭션 시작" 개념
DB에서 커밋 모드가 존재한다.
트랜잭션을 시작한다는 개념은 자동 커밋 모드를 끈다는 것이다. (수동 커밋 모드)
set autocommit false; DB의 기본 설정으로는 autocommit이 true로 설정되어있다..
-> 그래서 SQL 쿼리 한줄 한줄 실행 할때마다 바로바로 commit이 수행되는 것이다.
트랜잭션을 시작하고 나서는..
SQL을 한줄 한줄 수행하면, 임시로 세션이 가지고 있다가 (다른 세션에서는 볼 수 없음, 격리)
커밋을 하면 한번에 DB에 반영된다. (장애로 인한 롤백의 경우 DB가 변경되지 않는다.)
코드 상 트랜잭션의 위치
트랜잭션의 개념상 하나의 비즈니스 로직 기능 단위로 걸어야 하므로..
비즈니스 로직이 위치한 layer인 서비스 계층에 주로 위치한다.
(트랜잭션을 사용하는 동안 같은 커넥션을 유지해야 같은 세션을 사용할 수 있다.)
-> 이러면.. 순수해야할 서비스 계층이 .. DB접근 기술 코드 의존성이 생긴다...
-> 트랜잭션 추상화로 해결한다. (DB접근 기술이 바뀌더라도 서비스 계층 코드는 유지 가능)
(DB접근 기술 : JDBC, JPA, MyBatis 등)
-> 스프링은 PlatformTransactionManager라는 인터페이스로 트랜잭션 추상화를 하였다.
-> 서비스 계층에 의존성 주입으로 DB접근 기술에 따른 구현체를 다르게 주입해준다.
(JDBC의 경우 DataSourceTransactionManager 주입)
PlatformTransactionManager
트랜잭션 매니저라 부른다.
트랜잭션 추상화를 위한 스프링이 제공하는 인터페이스이다.
getTransaction 메서드 : 호출 하면, 트랜잭션을 시작할 수 있는 메서드이다.
commit 메서드 : 호출 하면, SQL수행 결과를 실제 DB에 한번에 반영한다.
rollback 메서드 : 호출 하면, 트랜잭션 시작 이후 수행된 SQL 수행 결과를 롤백한다.
(다른 세션 기준에서는 바뀌지 않음)
<참고>
TransactionStatus는 getTransaction을 수행하면 리턴되는 객체로..
트랜잭션의 상태 정보가 담겨져 있다.
commit, rollback 호출 시, 파라미터로 넘겨주면 된다.
해당 인터페이스에는 커넥션 관련 메서드(획득, 반환)는 존재하지 않는다
-> 인터페이스의 구현체 생성시, DataSource를 의존성 주입하는데..
-> DataSource가 커넥션 획득, 반환에 대한 작업을 한다.
DataSourceTransactionManager
PlatformTransactionManager 인터페이스의
JDBC용 구현체이다.
DataSource를 생성자에서 의존성 주입 받는다.
(그래야.. 커넥션도 얻고.. 커밋, 롤백 등을 수행할 수 있다.)
트랜잭션 동기화 매니저
트랜잭션이 필요 없을 때는.. repository 계층에서 DataSource를 통해 커넥션을 획득하였다.
하지만.. 트랜잭션 개념이 등장하며.. 서비스계층에서 트랜잭션을 시작해야 하므로..
서비스 계층에서 커넥션을 획득해야 한다.
따라서.. 서비스 계층에서 획득한 커넥션을 repository 계층으로 넘겨줄 필요가 생겼다.
이를 위한 클래스가 트랜잭션 동기화 매니저이다.
서비스 계층에서는 DataSource를 가지고있는 PlatformTransactionManager의 구현체가 커넥션을 생성한다.
생성하면 트랜잭션 동기화 매니저에 해당 커넥션을 보관한다.(스레드 로컬 개념 사용)
비즈니스 로직이 수행되며.. repository 계층의 메서드가 호출되면..
해당 메서드에서는..
Connection con = DataSourceUtils.getConnection(dataSource); 를 호출하여 커넥션을 받을 수 있다.
(트랜잭션 동기화 매니저에 보관되어있던 커넥션이 반환된다.)
DatasourceUtils.releaseConnection(con, dataSource); 를 호출하면.. 커넥션을 닫지 않고 다시 트랜잭션 동기화 매니저에 보관한다.
<참고>
트랜잭션 동기화 매니저에 해당 커넥션이 없을 경우엔..
getConnection을 호출하면, 커넥션이 생성(커넥션 풀에서 새로 받게)되고..
releaseConnection을 호출하면, 커넥션이 종료(커넥션 풀에 반환)된다.
트랜잭션 동기화 매니저 사용 시 장점
service 계층에서 repository 계층의 메서드 호출 시, 커넥션 정보를 파라미터로 넘겨주지 않아도 되서
파라미터에 DB 접근 기술에 대한 의존성이 제거 되었다.
다음글이전글이전 글이 없습니다.댓글