1、未配置事务管理器
@Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
2、内部方法调用了目标事务方法或者事务方法调用了目标事务方法
因为:AOP
使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成。内部方式调用时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效。
第一种:内部方法调用了目标事务方法,此时事务不生效。
@Service
public class OrderServiceImpl implements OrderService {
public void update(Order order) {
updateOrder(order);
}
@Transactional
public void updateOrder(Order order) {
// update order
}
}
第二中情况:内部事务方法调用目标事务方法且申明开启新事务,此时事务不生效,因为
还是内部方法间的调用,spring容器会为每一个事务方法生成一个动态代理类,而且每个动态代理类只管理一个事务。故不会生效
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void update(Order order) {
updateOrder(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrder(Order order) {
// update order
}
}
解决方法一:
改为2个不同的类调用,代码:
@Service
public class TestA implements OrderService{
@Autowired
private TestB testB;
@Transactional(rollBackFor = Exception.class)
public void update (Order order){
testB.updateOrder(order);
}
}
@Service
public calss TestB implements OrderService{
@Transactional(rollBackFor = Exception.class ,propagation = Propagation.REQUIRES_NEW)
public void updateOrder(Order order){
//updateOrder
}
}
解决方法二:
通过自身的bean调用,代码如下:
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private OrderService orderSerivce;
@Tranactional(rollBackFor = Exception.class)
public void update(Order order){
orderService.updateOrder(order);
}
@Tranactional(rollBackFor = Exception.class)
public void updateOrder(Order order){
//update order
}
}
解决方法三: 通过ApplicationContext来获取bean,其本质和方法二一致;
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private ApplicationContext applicationContext;
@Tranactional(rollBackFor = Exception.class)
public void update(Order order){
((OrderService)applicationContext.getBean("orderService")).updateOrder(order);
}
@Tranactional(rollBackFor = Exception.class)
public void updateOrder(Order order){
//update order
}
}
解决方法四:AopContext来获取代理类,代码如下;
@Service
public class OrderServiceImpl implements OrderService{
@Tranactional(rollBackFor = Exception.class)
public void update(Order order){
((OrderService)AopContext.currentProxy()).updateOrder(order);
}
@Tranactional(rollBackFor = Exception.class)
public void updateOrder(order){
//update order
}
}
解决方法五:编程式事务,通过TransactionManager 的commit和rollback,来手动提交和回退事务,此方法避免了通过的动态代理生成代理类
关于这点为啥声明式事务会导致事务失效,推荐阅读我的另一篇文章,详细理解@Transactional的原理,生成方法
//编程式事务
public class OrderServiceImpl implements orderService{
@Autowired
@Qualifier("transactionManager")//获取事务管理器
private DataSourceTransactionManager transactionManager;
public void update(Order order){
//定义事务
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
//开启一个事务
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//获取当前开启的事务状态
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
try{
updateOrder(order);
//提交
transactionManager.commit(transactionStatus);
}catch (Exception e){
//回滚
transactionManager.rollback(transactionStatus);
logger.error("异常,已回滚",e);
}
}
public void updateOrder(Order order){
//update order 操作
}
}
3、异常被捕获或不是运行时异常
第一种情况:异常被捕获。如以下代码:
try{
//运行时异常代码
}catch(RuntimeException e){
//不重新抛出异常
}
解决方法:重新抛出异常或者不捕获
try{
//运行时异常代码
}catch(RuntimeException e){
new RuntimeException("错误!");
}
第二种情况:不是运行时异常
@Transactional
public void updateOrder(Order order) {
try {
// update order
} catch(Exception e) {
throw new Exception("更新错误");
}
}
解决方法一:指定回滚异常类型
@Transactional(rollBackFor=Exception)
public void updateOrder(Order order) {
try {
// update order
} catch(Exception e) {
throw new Exception("更新错误");
}
}
解决方法二:将Exception转为运行时异常
@Transactional(rollBackFor=Exception)
public void updateOrder(Order order) {
try {
// update order
} catch(Exception e) {
throw new RuntimeException("更新错误");
}
}
4、不是 public 方法
spring的官方文档里有一段这样的描述
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.
当使用代理的时候,应该将@Transactional注解在公共访问的方法上。如果用在 protected,private或者default访问权限的方法上,虽然不会报错,但是@Transactional注解不会起作用,可以考虑使用AspectJ
5、类没有被@service注解
如
public class MemberServiceImpl implement memberService{
@Transcational
public void updateMemberInfo(){
//
}
}
6、数据库引擎不支持事务
以 MySQL 为例,5.5.5 以前 默认的 MyISAM 引擎是不支持事务操作的,5.5.5 以后默认的InnoDB引擎 才支持事务。另外MySQL的存储引擎是针对表的,所以要注意数据库的版本和表的存储引擎。底层引擎不支持事务再怎么搞都是白搭。