Spring声明式事务报错"Transaction r
2017-11-05 本文已影响783人
小胖0_0
在HGXP项目的资质校验功能中出现了这样一个报错信息:"Srping Transaction rolled back because it has been marked as rollback-only“,很明显是事务管理中出的问题,再查看资质校验的代码找到出错的位置之后,觉得事情可能并不是这么简单,于是在网上搜集了一下相关的问题,发现出现这个问题的朋友并不在少数,这里简单分析、总结一下这个报错的原因和解决方法。
由于HGXP项目中资质校验的逻辑代码太长(一个校验方法足足有 1000多行),这里就借用网友写的测试方法:
首先定义一个声明了事务的类:
@Transactional
public void add(OperateLog entity)throws Exception {
// TODO Auto-generated method stub
operateLogDao.add(entity);
}
然后再定义一个类用来坐事务异常的测试,其中定义了两个声明了事务的方法:
@Transactional
public void save(Member member) throws Exception {
memberDao.add(member);
}
@Transactional
public void add(Member member) throws Exception {
try {
this.save(member);
/*
* 日志的title长度为10 我把值设置为add111111111111111111是为了造成异常
*/
OperateLog entity = new OperateLog("add111111111111111111", "1111");
operateLogService.add(entity);
} catch (Exception e) {
e.printStackTrace();
// throw e;
}
}
这里的关键就是那个throw e
,当它没有被注释掉的时候,该方法不会报rollback的错,只会报标题过长的错,如下:
Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column '_title' at row 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4072)
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 org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
因此我们可以发现,在spring中,在事务方法中调用多个事务方法时,spring将会把这些事务合二为一。当整个方法中每个子方法没报错时,整个方法执行完才提交事务(大家可以使用debug测试),如果某个子方法有异常,spring将该事务标志为rollback only。如果这个子方法没有将异常往上整个方法抛出或整个方法未往上抛出,那么改异常就不会触发事务进行回滚,事务就会在整个方法执行完后就会提交,这时就会造成Transaction rolled back because it has been marked as rollback-only的异常,就如上面代码中未抛throw e 一样。如果我们往上抛了改异常,spring就会获取异常,并执行回滚。