관리 메뉴

IT.FARMER

오류- Lock wait timeout exceeded; try restarting transaction 본문

Spring/Spring Data JPA

오류- Lock wait timeout exceeded; try restarting transaction

아이티.파머 2023. 5. 25. 20:55
반응형

오류- Lock wait timeout exceeded; try restarting transaction

db에서 갑자기 락이발생했다고 하며 업데이트하는 쿼리가 타임아웃이발생하며 다음과 같은 오류가 발생했다. Lock wait timeout exceeded; try restarting transaction 검색을 해보니 정말 다양한 이유에 의해 락이 발생하는 것을 확인했고, 상황에 따라 다르게 해결해야 했다.

우리가 겪은 부분은 delete 와 insert,update 에대한 트렌젝션 처리기 한곳에 묶여있기 때문이었다. 삭제를 하고나서 트렉젝션으로 묶었으니 락이걸렸고 , 새로운 트렉젝션으로 업데으트를 하려니 업데이트나, 인설트를 하지 못해서 해당 오류가 나고있었다.

코드는 다음과 같다.


AClass {
    method_1() {
                this.method_2();
        bclass.method_3();    
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    method_2() {
            // delete logic
            QueryDSL의 JPAQueryFactory 를 사용
    }
}

BClass {

        @Transaction(propagation= Propagation.NESTED)
    method_3() {
            // insert , update logic
            JPA 사용
    }
}

원인

여기서 오류가 발생된 이유는 delete 한뒤 update 및 insert 를 하는 로직을 분리하여 transaction 을 처리하려 하였는데, method_2에서 transaction 처리가 안되있다고 하는 엉뚱한에러가나며 method_1에 @Teansaction을 붙여주면서 method1, 2, 3가 하나의 트렉젝션으로 묶이면서 발생되었다.

... 생략
@Transational
method_1() {
        this.method_2();
    bclass.method_3();    
}
... 생략
  • 이랬을경우 method 1의 트렌젝션 설정에 의해 통제되게 된다.

  • method_2 의 트렌젝션전략(propagation)은 REQIRES_NEW 임으로 method_1 의 상위 정책을 따르지 않고 새롭게 생성된 전략으로 사용된다.

  • method_3 의 전략은 NESTED 임으로 중첩된 트랜잭션을 사용한다.

  • 부모트랜젝션 즉 method_1이 잘못된경우엔(롤백되는경우) method3 의 데이터도 모두 롤백된다.

    • method2의 경우엔 독립적인 새로운 트렌젝션을 가지고 있기때문에 method1이 중간에 롤백되더라도 method2는 정상적인 delete 기능이 수행될수있다. 즉 method1의 롤백은 method2에 영향을 주지 않는다.
    • 이는 중첩 트렌젝션정책인 NESTED와는 다르게 REQUIRES_NEW 를 사용함으로 가능한것이다.
    • method2는 method1의 트렌젝션과는 분리되어 별개로 커밋 혹은 롤백 된다.

중첩트랜젝션이란 ?

  • 부모트렉젝션과는 독립적인 단위로 동작된다.
  • 일반적으로 부모트랙잭션의 컨텍스트 내에서 실행된다.
  • 이를 통해 중첩된 트랜젝션은 부모트랙젝션과는 별개로 롤백 또는 커밋될수있으며 부모트랜젝션에 영향을 주지 않고 독립적으로 제어 가능 하다.

해결방법

우리같은 경우엔

method_2(), method_3() 의 트렉젝션이 method_1() 에 물리지 않고 독립적으로되길 원했다. 그래서 method3()처럼 method_2()를 새로운 클레스로 분리하여 해당 문제를 해결 하였다.

AClass {
    method_1() {
                dClass.method_2();
        bClass.method_3();    
    }
}

BClass {
        @Transaction(propagation= Propagation.NESTED)
    method_3() {
            // insert , update logic
            JPA 사용
    }
}

DClass {
        @Transaction(propagation= Propagation.NESTED)
    method_2() {
            // insert , update logic
            JPA 사용
    }
}

이외에도 Lock wait timeout…. exception 이발생되는 경우는 여러 상황에 따라 다양하다. 결국엔 펑션이나 기능 혹은 다른 프로세스에서 트렌젝션으로 db table의 특정 데이터를 잡고(locked) 풀지 않는 경우에는 해당 에러가 발생될수있다.

  • sql 을 실행하여 락이 걸린 정보를 확인하고 조정 할 수있다.
select * from information_schema.INNODB_LOCKS;        -- 현재 Lock 정보
select * from information_schema.INNODB_LOCK_WAITS;   -- Lock을 대기 정보
select * from information_schema.INNODB_TRX;          -- 트랜잭션 상태

보통 데이터가 적은경우에는 이런일이 발생되지 않지만, 시간이 지나며 데이터가 많이 쌓일수록 배치에서는 이런일들이 종종 일어날수있다.( 예를들어, 데이터재수집 처럼 삭제하고 다시 저장할경우) 이처럼 트렉젝션 범위는 chunk 단위로 지나치게 길지 않도록 조정하여 주거나, 트렌젝션을 분리 시키는 방법을 사용하면 해결 방법이 될것이다.

참고자료

MySQL Lock wait timeout exceed

MySQL Lock wait timeout exceed

Lock wait timeout exceeded; try restarting transaction 발생 이유와 해결

반응형