首先要考虑所使用的数据库是不是支持事务性的,针对mysql必须使用innodb引擎来支持事务。
SHOW ENGINES;查看当前引擎状态。
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
其次,要注意transactional要捕获的是运行时异常RuntimeException。
在业务代码中,有如下两种情况,比如:
throw new RuntimeException("xxxxxxxxxxxx"); 事务回滚
throw new Exception("xxxxxxxxxxxx"); 事务没有回滚
1).
spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚, “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常” ,要想捕获非运行时异常则需要如下配置:
解决办法:
1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。
2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
</tx:attributes>
</tx:advice>
3.针对我们自己抛出的异常,可以通过rollbackFor属性来让事务去识别。
例如:
其次,如果我们定义多个数据源,而针对每个数据源也都定义相应的事务管理器,这个时候如果我们相用指定的事务管理器去回滚我们指定的业务模块。即通过value属性即可来制定唯一的事务管理器:
3.针对我们自己抛出的异常,可以通过rollbackFor属性来让事务去识别。
例如:
@Transactional(rollbackFor={RuntimeException.class,
CommonException.class})
public void test3(User user1) throws CommonException {}
这些都没有问题,就要开启日志,把启动日志打印出来,查看一下是不是我们定义的事务管理器扫描是否成功。有没有进行声明:
<tx:annotation-driven transaction-manager="transactionManager" />放置位置对不对,通常我们放在数据源配置完成,事务管理器定义完成之后声明,一定要注意,spring service bean的扫描早于这个声明之前。也有可能声明放在controller,而去service层加注解显然是不行的。
个
TransactionManager,那么对于只需要一个事务管理的方法,问题就简单多了:
@Transactional(value = "TransactionManager1") public void test(String a) { // business operation }
这里稍微提一下:
这里稍微提一下:
针对多数据库源可以使用
Spring + Atomikos 分布式事务实现方式来实现声明式事务,也可以切面编程来实现编程式事务。