spring@Transactional注解的方法报死锁异常后部分回滚的原因何在?

shower 2015-11-03 10:56:08
废话不多说,直接上代码:

service接口方法:
public ClassA executeFun(ClassC c ,ClassD d);


service接口方法实现类:
@Override
@Transactional
public ClassA executeFun(ClassC c ,ClassD d){
ClassB b = new ClassB();
保存b;
更新c;
更新d;
}

当service接口方法实现类代码执行完进行事务提交时抛出(更新c的死锁)异常:org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.LockAcquisitionException: Deadlock found when trying to get lock; try restarting transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.LockAcquisitionException: Deadlock found when trying to get lock; try restarting transaction
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.LockAcquisitionException: Deadlock found when trying to get lock; try restarting transaction
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1387)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:80)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
... 52 more
Caused by: org.hibernate.exception.LockAcquisitionException: Deadlock found when trying to get lock; try restarting transaction
at org.hibernate.dialect.MySQLDialect$1.convert(MySQLDialect.java:392)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at com.sun.proxy.$Proxy632.executeUpdate(Unknown Source)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3189)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3087)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3416)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:276)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
... 53 more
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:1066)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4187)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4119)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
... 69 more
出现的结果就是:更新对象ClassB的事务没有回滚;更新对象ClasssC的事务回滚了;更新对象ClassD的事务回滚了。
注:1、数据库是mysql innodb;
2、抛出的异常(死锁异常)是运行时异常;

最后请教各位大侠:spring@Transactional注解的方法报死锁异常后部分回滚的原因何在?有什么解决方案?



...全文
1561 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhenglichenboy 2017-08-29
  • 打赏
  • 举报
回复
你首先确定你service所在的类有没有别的 方法也在操作那个表,同时那个方法却在另一个事务种,如果有就会死锁,因为你其中一个事务没有commit,在执行中,另一个事务的写操作是会死锁的
shower 2015-11-06
  • 打赏
  • 举报
回复
引用 4 楼 defonds 的回复:
[quote=引用 楼主 shower2010 的回复:] 注:1、数据库是mysql innodb;
这句话有所欠妥。 MySQL 的存储引擎不是在建库时定义的,是在建表 DDL 时声明的,同库里可以有多种类型的存储引擎的表,每个表的存储引擎未必一致。 如果你的 spring 事务配置没问题,我怀疑是你的类 B 对应的表存储引擎可能是 MyISAM 所致。 查看你的实体类 B 对应的表(比如是 TABLE_B)的存储引擎是否是 InnoDB: SHOW CREATE TABLE TABLE_B; 如果结果是 ENGINE=MyISAM,那么就是它的原因了。[/quote] 非常感谢,此问题的原因正如Defonds所说的一样,实体B对应的表的存储引擎是 MyISAM 所致。 我的mysql默认的存储引擎是innoDB,但是这个表在创建时给指定为MyISAM了。 再次谢谢各位!
Defonds 2015-11-03
  • 打赏
  • 举报
回复
引用 楼主 shower2010 的回复:
注:1、数据库是mysql innodb;
这句话有所欠妥。 MySQL 的存储引擎不是在建库时定义的,是在建表 DDL 时声明的,同库里可以有多种类型的存储引擎的表,每个表的存储引擎未必一致。 如果你的 spring 事务配置没问题,我怀疑是你的类 B 对应的表存储引擎可能是 MyISAM 所致。 查看你的实体类 B 对应的表(比如是 TABLE_B)的存储引擎是否是 InnoDB: SHOW CREATE TABLE TABLE_B; 如果结果是 ENGINE=MyISAM,那么就是它的原因了。
Defonds 2015-11-03
  • 打赏
  • 举报
回复
@Override
@Transactional
public ClassA executeFun(ClassC c ,ClassD d){
ClassB b = new ClassB();
保存b;
更新c;
更新d;
}

这段代码,如果"更新c;"这句抛了异常,那么"更新d;"也就不会执行了吧,
引用 楼主 shower2010 的回复:
更新对象ClassB的事务没有回滚;更新对象ClasssC的事务回滚了;更新对象ClassD的事务回滚了。

既然没有执行"更新d;",那么也就谈不上“更新对象ClassD的事务回滚了”。
此外,更新c的死锁,那么也就是说没有对c进行更新,也谈不上“更新对象ClasssC的事务回滚了”。
无论如何,同一事务中后续代码抛了异常,前边数据库操作不应该不回滚,因此我怀疑你的 spring 事务控制压根儿就没起作用。
shower 2015-11-03
  • 打赏
  • 举报
回复
试过了,不行!
boy.gan 2015-11-03
  • 打赏
  • 举报
回复
在整个方法前加上 @Transactional(rollbackFor=Exception.class)

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧