Spring/JPA

DB 개념 + JPA concurrency control

공대키메라 2022. 3. 14. 23:11

필자는 금일 전화면접을 보았다. 

 

여기서 질문을 몇개 하셨는데 대답을 잘 못했다!(슬픔...)

 

하지만 괜찮다.... 절망만 하지 말고 이에 대한 정보를 최대한 찾아서 내것으로 만들어 보겠다.

 

오늘은 이와 관련된 정보를 찾아서 정리하겠다

 

1. Transaction이란?

 

트랜잭션이란 무엇일까?

 

데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위이다.

 

DB의 상태를 변형시킨다는 이야기는 무엇일까?

 

SELECT, UPDATE, INSERT, DELETE와 같은 행동을 뜻한다. 

 

트랜잭션에는 4가지의 특징이 있다.

 

  1. 원자성 : DB에 모두 반영되거나, 전혀 반영되지 않거나한다!
  2. 일관성 : 작업 처리의 결과가 항상 일관되어야 한다. 
  3. 독립성 : 하나의 트랜잭션은 다른 트랜잭션에 끼어들 수 없고 마찬가지로 독립적이다
  4. 지속성 : 트랜잭션이 성공적으로 완료되면 영구적으로 결과에 반영되어야 한다.

 

Commit : 하나의 트랜잭션이 성공적으로 끝났고, DB가 일관성있는 상태일 때 이를 알려주기 위해 사용하는 연산

Rollback : 하나의 트랜잭션 처리가 비정삭적으로 종료되어 트랜잭션 원자성이 '깨진 경우, 트랜잭션이 정상적으로 종료되지 않았을 때, last consistent state로  rollback할 수 있음

 

2.  JDBC란?

출처 : https://dyjung.tistory.com/50

 

3. Spring의 transaction 처리

 

다음 사이트에서 spring에서는 어떻게 이 transaction을 처리하는지 잘 정리가 되어있다.

https://www.tutorialspoint.com/spring/spring_transaction_management.htm

Spring framework provides an abstract layer on top of different underlying transaction management APIs. Spring's transaction support aims to provide an alternative to EJB transactions by adding transaction capabilities to POJOs. Spring supports both programmatic and declarative transaction management. EJBs require an application server, but Spring transaction management can be implemented without the need of an application server.

스프링 프레임워크는 다른 기저에 깔린 transaction management APIS들 위에 abstract layer를 제공한다. 

스프링의 트랜잭션은 POJO(Plain Old Java Object)에 트랜젝션 능력을 더하면서 EJB 트랜잭션에 대안을 제공하는것을 목표로 한다. 스프링은 programmatic and delarative 트랜잭션 관리를 둘 다 제공한다.  EJB는 어플리케이션 서버를 요구하지만, 스프링 트랜잭션 관리는 application server 필요성이 없이 시행될 수 있다.

 

Local VS Global Transactions

Local transaction management can be useful in a centralized computing environment where application components and resources are located at a single site, and transaction management only involves a local data manager running on a single machine. Local transactions are easier to be implemented.

Global transaction management is required in a distributed computing environment where all the resources are distributed across multiple systems. In such a case, transaction management needs to be done both at local and global levels. A distributed or a global transaction is executed across multiple systems, and its execution requires coordination between the global transaction management system and all the local data managers of all the involved systems.

 

Local Transaction management 과 Global Transaction management에 대해 설명한다. 

 

Local Transaction Management란 하나의 사이트에 위치한 application의 구성과 자원이 집중된 컴퓨팅 환경에서 쓰이고 유용한 management이다. 

 

Global Transaction Mangement란 여러 시스템이 거쳐 분산된 자원이 있는, 분리된 컴퓨팅 환경에서 요구되는 management이다. 이런 경우에 결국 local, global level에서 두개가 다 필요하다.(전자와 후자의 조화가 필요하다.)

 

Programmatic vs. Declarative

스프링은 두 타입의 transaction 관리를 제공한다. 

  • Programmatic Transacton Management : 프로그래밍의 토움으로 트랜잭션을 관리해야 하는 것을 의미. 고도의 유연성을 제공하지만 유지하기 어렵다.
  • Declarative Transaction Management : 비즈니스 코드로부터 트랜잭션 관리를 분리하는 것을 의미. 트랜잭션 관리를 위해 오직 XML 기반의 configuration을 사용한다. 

그리고 이 두개에 대해 설명하고 있다. 

 

Declarative transaction management is preferable over programmatic transaction management though it is less flexible than programmatic transaction management, which allows you to control transactions through your code. But as a kind of crosscutting concern, declarative transaction management can be modularized with the AOP approach. Spring supports declarative transaction management through the Spring AOP framework.

 

코드를 통해 트랜잭션을 관리하도록 해주는 programmatic transaction managemtn 보다 덜한 유연성에도 declarative transaction management 가 더 많이 선호된다. 하지만, 크로스 커팅 문제 때문에 declarative transaction management는 AOP 접근으로 모듈화 될 수 있다. 스프링은 declarative transaction management를 Spring AOP framework를 통해 제공한다. 

그리고 이와 관련된 Interface에 대해 설명하는데 너무 많은 관계로 읽어보길 바란다. 필자는 우선 JPA의 Consistency 관리가 더 궁금하다. 

 

4. 그럼 동시성 문제란 무엇일까?

 

동시성 문제란 무엇인가?

 

동시성 문제란 두 개 이상의 세션이 공통된 자원에 대해 모두 읽고 쓰는 작업(Read→Write) 을 하려고 하는 경우 발생할 수 있는 문제를 말한다.

 

이 동시성 문제라고 불리는 2가지 현상은 바로 일관성 없는 읽기와 손실되는 업데이트다.

 

  • 일관성 없는 읽기 : 같은 정보에 세션 1과 세션 2가 순서대로 접근했을 때 세션 2는 동시에 실행되고 있는 세션 1 때문에 데이터에 접근하는 시점마다 다른 값을 읽게되는 현상

일관성 없는 읽기는 복사본을 이용하면 쉽게 해결이 된다고 한다. 

이와는 좀 다르지만... JPA에서는 이와 비슷한 문제인제 bulk update실행시 문제가 있다.

 

예를 들어 bulk update를 실행시에는 영속 context에 변경된 객체를 반영하는 것 없이 DB에 바로 query를 실행해버린다. 우리 입장에서는 update가 나가는것을 볼 수 는 있지만 영속 context의 값이 변하지 않는다는 사실을 간과해서는 안된다! 물론 이런 경우에는 다시 데이터를 직접 조회를 해야 한다. 

 

  • 손실되는 업데이트 : 같은 정보에 세션 1과 세션 2가 순서대로 접근 시, 더 늦게 시작한 세션 2에 의해 세션 1의 변경사항이 무시되는 현상 

http://jaynewho.com/post/42

 

이 손실되는 업데이트를 방지하기 위한 방법으로는 크게 2가지가 있다.

 

그 두가지는 Pessimistic Lock 과 Optimistic Lock이다. 

 

5. Pessimistic Lock  Optimistic Lock

Pessimistic Lock

we can use pessimistic locking which uses database mechanisms for reserving more granular exclusive access to the data. We can use a pessimistic lock to ensure that no other transactions can modify or delete reserved data.

=> 이미 접근하고 있는 데이터를 수정하거나 삭제 자체를 못하게 막아버림(선점한다고 보면 된다. -> 누가 그만쓸 때 까지 사용이 불가능)

 

Optimistic Lock 

optimistic locking is based on detecting changes on entities by checking their version attribute. If any concurrent update takes place, OptmisticLockException occurs. After that, we can retry updating the data.

=> 접근은 가능한데 누가 물고 있는데 다른곳에서 업데이터 하려면 오류 발생. 

 

 

6. JPA  지원 기능 - pessimistic

 

pessimistic lock을 위해서 JPA에서는 pessimistic lock mode를 3개를 제공한다.

  • PESSIMISTIC_READ : 공유된 lock을 얻게 해주고 데이터가 업데이트되거나, 삭제되는것을 막음
  • PESSIMISTIC_WRITE : exclusive lock을 얻게 해주고 데이터가 읽거나, 업데이트 되거나, 삭제되는 것을 막음. 
  • PESSIMISTIC_FORCE_INCREMENT : PESSIMISTIC_WRITE처럼 작동하고 추가적으로 version이 있는 entity에 version 속성을 증가시킨다.

 

1. PESSIMISTIC_READ 

우리가 단지 데이터를 읽고, dirty reads(???? 변경 감지하듯이 그런 의미인듯)를 하기 싫다면, PESSIMISTIC_READ를 사용할 수 있다. update나 delete는 못한다. DB에서 간혹 PESSIMISTIC_READ를 지원하지 않으면 PESSIMISTIC_WRITE 사용이 가능하다. 

 

2. PESSIMISTIC_WRITE 

데이터에 락 요구를 필요로 하고, 그것을 변경하는 어떤 transaction은 PESSIMISTIC_WRITE lock이 필요하다.

JPA specification 에 따르면, PESSIMISTIC_LOCK을 유지하는 것은 다른 트랜션이 데이터를 읽고 업데이트하고 삭제하는 것을 막아준다. 

 

몇몇 DB시스템들은 reader들이 이미 막힌 data를 fetch하도록 multi 버전 동시 제어를 시행하는것을 명심해라!

(이말은 그러니까... PESSIMISTIC_WRITE로 설정을 해도 fetch의 경우 접근이 가능할 수도 있다는 것 같다.)

 

3. PESSIMISTIC_FORCE_INCREMENT

PESSIMISTIC_WRITE와 비슷하지만, version이 있는 entity(@Version 어노테이션을 가진 entity들)들과 같이 쓰려고 도입됐다. 

versioned한 entity들의 어떤 업데이트들도 PESSIMISTIC_FORCE_INCREMENT lock이 있다면 진행될 수 있다. 

 

그것이 versioned하지 않은 entity를 위해 PESSIMISTIC_FORCE_INCREMENT를 지원할지 아닐지는 persistence provider에게 달렸다. 만약 그렇지 않다면, PersistanceException을 던진다. 

 

이 PESSIMISTIC과 관련된 오류는 다음과 같다.

 

  • PessimisticLockException
  • LockTimeoutException
  • PersistenceException

개념을 잘 알고 있으면 사용하는 것은 큰 문제가 아니라고 생각된다. 해당 사이트를 참조하면 자세히 설명되어있다. 

 

optimistic도 마찬가지로 기능은 비슷하다. 다음 사이트에서 참조하면 굉장히 비슷하다. 

 

https://www.baeldung.com/jpa-optimistic-locking

 

 

 

 

 

'Spring > JPA' 카테고리의 다른 글

@Entity 설정 Annotation 정리  (0) 2022.03.17