spring事务不起作用的几种情况及其解决方法

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的原理,生成方法

spring 事务_手执格桑花的小黑的博客-CSDN博客

//编程式事务
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的存储引擎是针对表的,所以要注意数据库的版本和表的存储引擎。底层引擎不支持事务再怎么搞都是白搭。

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值