[SPRING] "잠금을 얻으려고 할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작하십시오. "
SPRING"잠금을 얻으려고 할 때 교착 상태가 발견되었습니다. 트랜잭션을 다시 시작하십시오. "
내 응용 프로그램 (자바 스프링 코어)은 동시에 실행되고 db에 액세스하는 여러 스레드가 있으며 일부 피크 타임에는 예외가 발생합니다.
07:43:33,400 WARN [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1213, SQLState: 40001
07:43:33,808 ERROR [org.hibernate.util.JDBCExceptionReporter] Deadlock found when trying to get lock; try restarting transaction
07:43:33,808 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: could not insert: [com.xminds.bestfriend.frontend.model.Question]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:107)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2436)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2856)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147)
at com.xminds.bestfriend.consumers.Base.onMessage(Base.java:96)
at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:339)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:535)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:495)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:467)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)
at java.lang.Thread.run(Thread.java:662)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1065)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2719)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2450)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2371)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2355)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2416)
... 25 more
내 코드가 보인다.
try
{
this.consumerTransactionTemplate.execute(new TransactionCallbackWithoutResult(){
@Override
protected void doInTransactionWithoutResult(
TransactionStatus status)
{
process();
}
});
}
catch(Exception e){
logger.error("Exception occured " , e);
//TODO: Exception handling
}
해결법
-
==============================
1.MySQL의 InnoDB 엔진은 행 수준의 잠금 기능을 제공하므로 코드가 단일 행을 삽입하거나 업데이트 할 때 (특히 업데이트되는 테이블에 여러 개의 인덱스가있는 경우)에도 교착 상태가 발생할 수 있습니다. 교착 상태로 인해 트랜잭션이 실패 할 경우 트랜잭션을 다시 시도하기 위해이 문제를 해결하기위한 코드를 설계하는 것이 가장 좋습니다. MySQL 교착 상태 진단 및 가능한 해결 방법에 대한 유용한 정보가 여기에 있습니다.
MySQL의 InnoDB 엔진은 행 수준의 잠금 기능을 제공하므로 코드가 단일 행을 삽입하거나 업데이트 할 때 (특히 업데이트되는 테이블에 여러 개의 인덱스가있는 경우)에도 교착 상태가 발생할 수 있습니다. 교착 상태로 인해 트랜잭션이 실패 할 경우 트랜잭션을 다시 시도하기 위해이 문제를 해결하기위한 코드를 설계하는 것이 가장 좋습니다. MySQL 교착 상태 진단 및 가능한 해결 방법에 대한 유용한 정보가 여기에 있습니다.
Spring에서 AOP를 통한 교착 상태 재 시도의 흥미로운 구현은 여기에서 볼 수있다. 이렇게하면 교착 상태가 발생했을 때 다시 시도하려는 메소드에 주석을 추가하기 만하면됩니다.
-
==============================
2.Emir의 대답은 훌륭하고 당신이 얻고있는 문제를 설명합니다. 그러나 나는 봄 재 시도를 시도하는 것이 좋습니다.
Emir의 대답은 훌륭하고 당신이 얻고있는 문제를 설명합니다. 그러나 나는 봄 재 시도를 시도하는 것이 좋습니다.
주석 (들)을 통해 재시도 패턴을 구현하는 훌륭한 프레임 워크입니다.
예:
@Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500)) public void doSomethingWithMysql() { consumerTransactionTemplate.execute( new TransactionCallbackWithoutResult(){ @Override protected void doInTransactionWithoutResult( TransactionStatus status) { process(); } }); }
어떤 예외가 발생하면 백 오프 정책이 500ms 인 doSomethingWithMysql () 메서드의 최대 4 배를 다시 시도 (호출)합니다.
-
==============================
3.이런 종류의 오류가 발생하면 "교착 상태가 감지되었습니다". 쿼리 실행을 검사하고 두 개 이상의 동시 트랜잭션으로 인해 교착 상태가 발생할 수 있는지 확인해야합니다.
이런 종류의 오류가 발생하면 "교착 상태가 감지되었습니다". 쿼리 실행을 검사하고 두 개 이상의 동시 트랜잭션으로 인해 교착 상태가 발생할 수 있는지 확인해야합니다.
이러한 트랜잭션은 교착 상태를 피하기 위해 동일한 순서로 데이터베이스 잠금을 획득해야합니다.
from https://stackoverflow.com/questions/17747906/getting-deadlock-found-when-trying-to-get-lock-try-restarting-transaction by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 왜 트랜잭션은 RuntimeException에서 롤백하지만 SQLException은 그렇지 않다. (0) | 2019.01.11 |
---|---|
[SPRING] 스프링 빈 정의의 우선 순위는 무엇입니까? (0) | 2019.01.11 |
[SPRING] Spring MVC : 컨트롤러 메소드 매개 변수에 요청 속성을 바인드한다. (0) | 2019.01.11 |
[SPRING] 서비스 계층이 정말로 필요합니까? (0) | 2019.01.11 |
[SPRING] 좋은 아이디어 로깅을 위해 Spring AOP를 사용하고 있습니까? (0) | 2019.01.11 |