2013-07-19 23 views
18

Ứng dụng của tôi (java mùa xuân-core) có một số đề chạy đồng thời và truy cập vào db, tôi nhận được ngoại lệ trong một số peaktimeBắt "Deadlock tìm thấy khi cố gắng để có được khóa; cố gắng khởi động lại giao dịch"

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 

Mã của tôi trông

try 
{ 
     this.consumerTransactionTemplate.execute(new TransactionCallbackWithoutResult(){ 

        @Override 
        protected void doInTransactionWithoutResult(
          TransactionStatus status) 
        { 
         process(); 
        } 

       }); 

    } 
    catch(Exception e){ 
    logger.error("Exception occured " , e); 
     //TODO: Exception handling 
    } 

Trả lời

18

InnoDB thể thao động cơ hàng cấp khóa MySQL, mà có thể dẫn đến sự bế tắc ngay cả khi mã của bạn được chèn hoặc cập nhật một hàng duy nhất (đặc biệt nếu có một số chỉ số trên bàn đang được cập nhật). Đặt cược tốt nhất của bạn là thiết kế mã xung quanh điều này để thử lại một giao dịch nếu nó không thành công do bế tắc. Một số thông tin hữu ích về chẩn đoán bế tắc MySQL và cách giải quyết có thể có sẵn here.

Thực hiện thú vị về thử lại bế tắc qua AOP trong mùa xuân có sẵn here. Bằng cách này, bạn chỉ cần thêm chú thích vào phương thức bạn muốn thử lại trong trường hợp bế tắc.

3

Câu trả lời của Emir thật tuyệt vời và nó mô tả sự cố bạn đang gặp phải. Tuy nhiên tôi đề nghị bạn thử spring-retry.

Đó là một khuôn khổ tuyệt vời để triển khai mẫu thử lại thông qua (các) chú thích.

Ví dụ:

@Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500)) 
public void doSomethingWithMysql() { 
    consumerTransactionTemplate.execute(
      new TransactionCallbackWithoutResult(){ 
       @Override 
       protected void doInTransactionWithoutResult(     
         TransactionStatus status) 
       { 
        process(); 
       } 

      }); 
} 

Trong mọi trường hợp ngoại lệ, nó sẽ thử lại (cuộc gọi) lên đến 4 lần so với phương pháp doSomethingWithMysql() với một chính sách backoff của 500ms

-1

Khi bạn đối mặt với loại này lỗi "phát hiện bế tắc". Bạn nên kiểm tra việc thực hiện truy vấn và xác minh xem hai hoặc nhiều giao dịch đồng thời có thể gây ra bế tắc không.

Các giao dịch này sẽ có được khóa cơ sở dữ liệu theo cùng thứ tự để tránh bế tắc.

+0

Điều gì xảy ra nếu vấn đề không có trong mã nhưng trong một hệ thống đồng thời cố gắng truy cập cùng một tài nguyên cùng một lúc? –