여러 유저에게 같은 데이터에 대해서 많은 요청이 들어왔을 때 일반적인 JPA사용에서는 일부 요청이 유실될 수도 있다고 합니다.
그런데, 이 일부 요청에 대해서는 항상 다 저장을 해야하는 상황도 오고 데이터를 수정시키지 않아야 할 경우도 있습니다.
저도 오늘 실무를 통해 경험을 했습니다.
오늘 실무를 통한 경험은 게시판에 있는 게시물의 조회 수 증가에 대한 예시가 될 것 같습니다.
게시판의 게시물을 동시다발적으로 누른다면, 조회 수는 모두 업데이트 해야 합니다.
JPA의 일반적인 요청을 사용한다면, 일부 요청에 대해서 유실이 되어 조회 수가 업데이트가 안 될 수 있습니다.
하지만 모든 요청에 대해서 조회 수를 모두 업데이트 시켜줘야합니다.
이러한 문제를 해결하기 위해서는 JPA에서 낙관적 락(Optimistic Lock) 그리고 비관적 락(Pessimistic Lock)을 알아보았습니다.
낙관적 락(Optimistic Lock)
- 데이터 갱신 시 충돌이 발생하지 않은 것이라고 가정함.
- 데이터 수정에 대해 충돌이 났을 경우 후에 업데이트 한 사람의 변경 사항은 무시된다.
- 다른 트랜잭션이 해당 데이터를 변경하지 않을 경우 변경.
비관적 락(Pessimistic Lock)
- 트랜잭션의 충돌이 발생한다고 가정하고 우선 락을 거는 행위입니다.
- 트랜잭션 안에서 서비스 로직이 실행되어야 합니다.
- 데이터 수준에서 엔티티 잠금을 합니다.
낙관적 락과 비관적 락을 찾아본 결과,
1. 동시다발적으로 요청을 한다.
2. 트랜잭션의 충돌이 발생할 수 있다. 락을 걸어야 한다.
3. 조회 수 업데이트하는데에 락을 걸어야 한다.
라는 것을 보고 비관적 락을 걸고 Pessimitic_write를 통하여, 배타적 잠금을 이용하였습니다. 그리고 추가적으로, 락이 길어지면 안 되기 때문에, QueryHint를 통하여 3초 타임 아웃을 주었습니다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="3000")})
Stock findById(String id)
그 후 curl을 통하여 15000개의 게시판 조회를 하여, 결과 값을 확인한 결과 모두 조회가 업데이트하는 것을 볼 수 있었습니다.
회고
회사에서 JPA를 사용하여 프로젝트를 진행 중입니다.
하지만 기본적인 JPA를 사용하는 것이 가능하지, 이렇게 락에 대한 컨트롤이 아직까지는 부족한 것 같습니다.
' 요번 해는 딴 거 공부하지 말고, 리눅스랑 SQL부터 확실히 더 짚고 넘어가는 게 어때? '라는 저희 회사 이사님의 말이 떠오르는군요.
시간을 내서 리눅스랑 SQL과 친해지는 시간을 좀 가져야 되겠습니다.
읽어주셔서 감사합니다. 저는 요가하러 가보겠습니다.