mysql

mysql의 트랜잭션 2개의 경합시 동작

rkrkrr0101 2024. 10. 31. 21:50

만약 트랜잭션 두개에서,각각 유니크칼럼이 겹치는 insert나 update를 동시에 수행한다면,두번째 트랜잭션의 쿼리는 첫번째 트랜잭션의 쿼리가 커밋이나 롤백될때까지 무한대기에 들어가게된다

이게 어케 잘못꼬이면(그 철학자 젓가락같은거,그래서 비관적락에서는 항상 조회순서를 통일해줘야함) 데드락이 생기기 매우 쉽다

 

단 이때 select의 결과는 바뀌지않는다(mysql의 gap lock으로 락이 걸려있기때문)

first와 second는 둘다 유니크

1번트랜잭션 start transaction;
2번트랜잭션 start transaction;
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 0개
1번트랜잭션 insert into lock_test(first,second) values("22","bb");//id는 자동생성
1번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 1개
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 0개
2번트랜잭션 insert into lock_test(first,second) values("22","bb")//1번 트랜잭션 성공실패까지 무한대기
1번트랜잭션 commit;//즉시 2번트랜잭션 대기 해제후 실패

 

이떄 특이한점은,

first와 second는 둘다 유니크

1번트랜잭션 start transaction;
2번트랜잭션 start transaction;
1번트랜잭션 insert into lock_test(first,second) values("22","bb");//id는 자동생성
1번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 1개
1번트랜잭션 commit;//1번트랜잭션 성공
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 1개
2번트랜잭션 insert into lock_test(first,second) values("22","bb")//즉시 유니크실패

 

이렇게 2번트랜잭션과 1번트랜잭션이 동시에 진입하고,2번트랜잭션이 select를 날리지않은 상태로 1번트랜잭션이 먼저 insert를 하고 성공하면,그 결과가 2번트랜잭션의 select와 insert에 적용된다는것과

 

만약 2번트랜잭션이 1번트랜잭션이 종료되기전에 해당 조건으로 select를 했다면

first와 second는 둘다 유니크

1번트랜잭션 start transaction;
2번트랜잭션 start transaction;
1번트랜잭션 insert into lock_test(first,second) values("22","bb");//id는 자동생성
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 0개
1번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 1개
1번트랜잭션 commit;//1번트랜잭션 성공
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 0개
2번트랜잭션 insert into lock_test(first,second) values("22","bb")//즉시 유니크실패
2번트랜잭션 select * from lock_test where first="22" and second="bb";//결과갯수 0개

2번트랜잭션의 select의 결과값에는 무조건 2번트랜잭션의 첫번째 select의 결과값만 표시되지만(캐시같은느낌),insert는 즉시실패하고,그지점에서 다시 select를 날려봐도 select에는 표시되지않는다는것이다

 

즉 mysql의 innoDB의 특성상,select for update가 아니라면 팬텀리드는 일어나지않는다

다만 트랜잭션이 즉시 끝나지않으면,겹치는 부분을 접근하는 다른 어플리케이션이 무한대기에 빠질수 있으므로,트랜잭션에 들어갔다면 인서트나 업데이트가 나오고 나서부터 최대한 빨리 커밋하게해야한다

즉 인서트나 업데이트는 마지막에 몰아서하는게 안전할거같아보인다