skarltjr / Memory_Write_Record

나의 모든 학습 기록
0 stars 0 forks source link

트랜잭션 격리수준2는 동시성 문제를 해결할 수 있는건가? #129

Open skarltjr opened 1 year ago

skarltjr commented 1 year ago

개요:

트랜잭션 격리수준 레벨2는 동시성문제 해결 방법이 될 수 있을까?
Entity

@Entity
@NoArgsConstructor
@AllArgsConstructor
public class MyEntity {
    @Id
    @GeneratedValue
    private Long id;

    private int number;

    public void addNumber() {
        this.number++;
    }

    public int getNumber() {
        return this.number;
    }
}
Service.class

@Service
@RequiredArgsConstructor
public class ConcurrentService {
    private final MyRepo myRepo;

    @Transactional
    public void concurrentlyEdit() {
        MyEntity myEntity = myRepo.findAll().get(0);
        myEntity.addNumber();
    }

}
Test

  @Test
  void test() throws InterruptedException {
      CountDownLatch latch = new CountDownLatch(5);
      ExecutorService executorService = Executors.newFixedThreadPool(5);

      for (int i = 0; i < 5; i++) {
          executorService.execute(()->{
              service.concurrentlyEdit();
              latch.countDown();
          });
      }
      Thread.sleep(10000);
      System.out.println(myRepo.findAll().get(0).getNumber() + " hello");
  }

하고자하는것은

CountDownLatch latch = new CountDownLatch(5);은 5개의 스레드가 종료될때까지 기다릴거다
그리고 5개의 스레드를 실행시켜 동시에 myEntity의 number를 증가시킨뒤 올바르게 반영되는지 확인

만약 내가 이해한대로 트랜잭션 레벨2가 한 트랜잭션에서 데이터에 접근하는동안 다른 트랜잭션에서 해당 데이터를 수정할 수 없다면
절대 결과는 5가 나올 수 없다.

그럼 레벨2면 동시성 문제에 대한 걱정없이 막 쓰면되는거아냐?

격리수준 레벨2는 결국 락을 사용한다.
트랜잭션 격리수준 레벨2의 특징이 무엇인가? 레벨이 높아질수록 결국 동시성을 포기하고 무결성을 선택한다.

비관적락 사용시 문제점이 무엇이었는가?
- 트랜잭션 충돌을 예상해서 미리 락걸고 수행한다
- 그럼 결국 많은 요청이 들어오면 그 요청을 수행할때마다 락걸고 동작하고 이는 당연히 성능상 문제가 발생할 수 있다.
솔직히 말하자면 아직까진 락없이 성능을 유지하면서 동시성문제를 제어할 수 있는 방법이 무엇인지 모르겠다.
다만 지금처럼 알고있는 지식을 확인함으로써 다음에 이해해야할 내용을 보다 쉽게 이해할 수 있지 않을까한다
skarltjr commented 1 year ago

참고로 mysql에서

select for update 쿼리는 

조회하는 대상에 대해서 락을 통해
다른 트랜잭션에서 수정불가능하다.