스프링 트랜잭션 동기화와 DB Transaction isolation level 은 어떤 연관성이 있을까?

2023. 4. 6. 23:40카테고리 없음

트랜잭션 동기화

-트랜잭션 동기화라는 기술은 트랜잭션을 시작하기 위해 생성한 Connection 객체를 별도의 특별한 공간에 보관하고, 이 커넥션이 필요한 곳 (여기서는 DAO) 에서 커넥션을 꺼내 쓰는 방식이다.

 

근데 왜? 커넥션을 하나만  사용해야 하는가???

 

 

우선 DB에서의 트랜잭션에 대해서 이해해 보자 !

 

1. 사용자는 WAS,DB접근 툴을 통해서 DB에 접근 할수 있다. 사용자는 DB서버에 연결 요청을 하고 WAS는 이를 대신해서 

DB와 커넥션을 연결해 준다 . 

2. WAS의 커넥션/DB의 커넥션이 연결되면 DB는 세션을 하나  만들어둔다.

3. 커넥션을 통해 세션이 생성되면 WAS에서 DB로 오는 모든 요청은 DB세션이 처리하게 된다.

 

사용자가 커넥션을 닫거나 DB관리가 세션을 강제 종료하면 DB세션은 종료된다.

 

*세션::데이터베이스 접속을 시작으로, 여러 작업을 수행한 후 접속 종료까지의 전체 기간을 의미한다.

 

커넥션 풀은 기본적으로 여러 개의 커넥션을 가지고 있다. 

이 커넥션은 각각 DB 세션을 가지고 있다. 사용자는 요청할 때 마다, 서로 다른 커넥션을 커넥션 풀로부터 제공을 받는다. 따라서 서로 다른 세션으로 DB에 접근하기 때문에 DB 세션의 동시성 문제는 제거된다. 

 

세션을 통해서 데이터가 변경 삭제 될때 까지 해당 데이터의  ACID를 보장한다.(트랜젝션) 

1.세션 안에는 여러개의 트랜젝션이 존재 할수 있으며 (하나이상의 ), 일반적으로 데이터 베이스는 여러 곳에서 동시에 접근이 가능하기 때문에 많은 세션이 동시에 연결 될수 있다.

 

2;세션은 데이터가 변경,삭제가 확정될때 까지 해당 데이터 조작을 분리 처리 함으로써 데이터와 테이블과의 관계를 보존하는 역할을 한다.

 

3.특정세션에서 조작중인 데이터는 트랜젝션이 커밋이 되기 전까지  다른 세션에서 조작 할 수 없다.

 

ACID?

 

Atomocity(원자성):다 되거나 다 안되거나  함으로 겨로가를 예측 할수 있어야 한다.
Consistency(일관성):데이터는 미리 정의된 규칙에서만 수정이 가능한 특성
Isolation(격리성, 고립성): 독립성, 트랙잭션을 수행하는 도중에 다른 연산 작업이 끼어 들지 못하도록 한다.
Durability(지속성):  한번 커밋된 트랜젝션의 내용은 영원히 적용되는 특성

 

 

결론:DB에서는  WAS와  연결된 커넥션을 사용하는데 이 커넥션이 생성이 되면  세션과 연결이 된다 . 이 세션은  사용자 마다 독립된 공간을 제공 !, 그렇기에 세션을 통해서 데이터에 트랜잭션 ACID를 보장한다.

 

 

 

스프링에서 트랜잭션에 이해해 보자 

 

 

어플리케이션에서 DB트랜잭션을 사용하려면 트랜잭션을 사용하는 동안 같은 커넥션을 유지해야 한다. 그래야 세션이 같게 유지가 된다 .

 

세션을 하나로 유지하는 방법과 그로인한 문제 

 

 1)커넥션을 파라미터로 전달하여 같은 커넥션이 사용되도록 유지

트랜잭션용 기능과 트랜잭션을 유지 하지 않아도 되는 기능으로 분리 필요

 2)JDBC 구현 기술이 서비스 계층에 누수되는 문제

트랜잭션 시작점은 비즈니스 로직이 있는 서비스 계층에서 시작되는데  서비스 계층에서 

 트랜잭션을 사용하기 위해서  JDBC기술에 의존하게 되고 결과적으로 비즈니스 로직보다 JDBC 를 사용하여 트랜잭션 처리하는 코드가 더 많아진다.

3)트랜잭션 적용 반복 문제 

 트랜잭션 적용 코드를 보다보면 try,catch,finally등 

 

이로인해 

스프링에서는 서비스 계층을 순수하게 유지할 수 있는 다양한 방법과 기술을 제공한다.

 

구현 기술에 따른 트랜잭션 사용법 

-구현 기술 마다 트랜잭션을 사용하는 방법이 다르다

-이럴경우 jdbc->jpa로 기술 변겅시 서비스 계층의 트랜잭션을 처리하는 모든 코드 변경 발생

트랜잭션 추상화 로 해결 

 

 

스프링은 트랜잭션을 추상화해서 제공할 뿐만 아니라, 실무에서 주로 사용하는 데이터 접근 기술에 대한 트랜잭션의 구현체도 제공한다, 우리는 필요한 구현체를 스프링 빈으로 등록하고 주입 받아서 사용하기만 하면된다 .

스프링 부트는 어떤 데이터 접근 기술을 사용하는지를 자동으로 인식해서 적절한 트랜잭션 매니저를 선택해서 스프링 빈으로 등록해 준다, 트랜잭션 매니저를 선택하고 등록하는 과정도 생략이 가능하다.

 

- 스프링  선언전 트랜잭션 AOP

스프링에서는 트랜잭션 처리를 지원하는데, 그 중 한 방법으로 @Transactional 어노테이션을 클래스 혹은 메서드 위에 추가할 수 있다.  이를 선언적 트랜잭션이라고 부른다. 

 

 

 

 

서비스 객체를 명확히 분리

 

JdbcTemplate 을 포함한 대부분의 데이터 접근 기술들은 트랜잭션을 유지하기 위해 내부에서 트랜잭션 동기화 매니저를 통해 리소스(커넥션)를 동기화 한다.

결론: 데이터베이스에서 제공하는 트랜잭션 기능을 사용하기 위해서는 세션을 하나로 유지해야 했다.  그러므로 인해서 서비스 로직에서 JDBC 같은 데이터 접근 기술에 의존적으로 됨으로써 서비스 로직이 복잡해지는 문제가 발생한다.  스프링에서 이것을 해결하는 방법으로  트랜잭션 매니저는 JDBC같은 데이터 접근 기술에 바로 의존하는 것이 아니라 인터페이스를 이용함으로   실제 구현체하고의 의존성 을 줄일 수 있었다.
또한  스프링에 선언적 트랜잭션을 통해서 서비스 로직이 아닌  서비스 로직에 프록시에서 트랜잭션을 처리 하여  트랜잭션을 처리하는 객체와 비즈니스 로직을 처리하는객체를 명확히 분리 시킬 수 있었다.
마지막으로 하나의 커넥션을 사용하기 위해서 트랜잭션 동기화 기술을 사용하여  DB접근시 하나의 세션에서 일련의 과정이 이루어 질수 있게 하였다.

 

 

 

다시 주제로 넘어와서 

스프링 트랜잭션 동기화와 DB Transaction isolation level 은 어떤 연관성이 있을까?

 

*트랜잭션 동기화 저장소 -> 작업 스레드마다 독립적으로 Connection 오브젝트를 저장하고 관리하기 때문에 다중 사용자를 처리하는 서버의 멀티스레드 환경에서도 충돌이 날 염려는 없습니다. 동시성 문제 해결 

 

여러 클라이언트가 같은 데이터에 접근 할때  트랜잭션을 서로 격리해서 다른 트랜잭션에 영향을 주지 못하게 하는데 

이때 격리 수준에 따라서 다양한 문제들이 발생한다.

 

 

*isolation (격리성)?

트랜잭션에서 일관성이 없는 데이터를 어느정도 허용할지의 수준을 의미한다.

 

*isolation level (트랜잭션 격리수준)?

1)동시에 여러 트랜잭션이 처리될 때, 특정  세션에 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할지 말지를 결정하는 것입니다. 

2)여러 트랜잭션이 동시에 수정을 일으키는 쿼리를 요청했을 때,
신뢰성, 일관성을 유지하면서도 높은 성능을 유지하는 균형
트랜잭션 격리를 하지 않고 신뢰성을 낮추는 대신 성능을 높일 수도 있고,
트랜잭션 격리를 극단적으로 가져가며 신뢰성을 높이는 대신 성능을 다소 포기할 수도 있습니다.

 

 

DB데이터 베이스 서버에서 격리성 

 

트랜잭션 속성에서도  격리성은  더욱 커넥션에 종속 될 수 밖에 없다.

그 이유는 커넥션에 대한 DB서버 정책으로써 트랜잭션 격리 수준을 설정할 수 있습니다.

-> 동시성 문제를 다룰떄는 사용하는 db의 기본 격리 레벨 을 알아야 한다 ,레벨 에 따른 동작 방식이 서로 다르다,

 

스프링에서 DB서버 기능을 사용하는 방법 

 

스프링 ->클라이언트가 서버에 커넥션을 맺고 요청을 전달하면,
이는 MySQL 서버 내에서 하나의 세션으로 동작하게 됩니다.
이처럼 요청할 때 클라이언트가SET TRANSACTION 명령어를 이용해
이번 요청에 한하여 트랜잭션 격리 수준을 다르게 설정할 수 있습니다.

이처럼 요청 시점에 트랜잭션 격리 수준을 다르게 설정하는 것은
스프링의 @Transactional 애너테이션에서 사용됩니다.
해당 애너테이션에 별다른 격리 수준 설정값을 전달하지 않으면,
해당 테이블에 적용되는 기본 트랜잭션 격리 수준을 적용합니다.
그러나 다른 격리수준 설정을 전달하면, 쿼리가 전달될 때 해당 격리 수준이 함께 전달되는 것입니다.

 

 

 

격리 수준은 다음과 같이 4가지로 정의할 수 있습니다.

  • READ UNCOMMITTED(커밋되지 않은 읽기)
  • READ COMMITTED(커밋된 읽기) ->커밋된 데이터만 읽기, 커밋된 데이터만 덮어쓰기가 가능하다 (커밋된 값과 트랜잭션 진행중인 값을 따로 보관, 행 단위 잠금사용  같은 데이터를 수정한 트랜잭션이 끝날때 까지 대기)
  • REPEATABLE READ(반복 가능한 읽기)
  • SERIALIZABLE(직렬화 가능)

-> 트랜잭션 격리 수준에 따라서 발생하는 상황들이 다른데 , 이걸 알아야 트랜잭션 하나가 커넥션에 종속 될 수 밖에 없는

이유를 알게된다.

 

 

 

 

 

 

 

 

 

1) 데이터 베이스 두개를 쓴다고치면 트랜잭션을 달았다면 누구에게 트랜잭션이 동작하는가?

2) 트랜잭션이 실패가 되면 둘다 롤백이 될까?

3) 하나는 되고 하나는 안될까?

 

 

-> 직접 테스트 진행해보기 

(mysql서버 두개를 만들어 놓고 두개다 연결을 시키고 트랜잭션널을 걸어서 테스를 해볼때 , 한명한테만 트랜잭션이 걸리는지, b한테만 걸리는지 등 
그렇다면 두개에 동시에 트랜잭션을 걸수 있는지  공부해보기 )

 

 

https://creampuffy.tistory.com/175