@Transaction注解哪些情况下会失效

文章详细阐述了Spring的@Transactional注解的使用规则,包括只能作用于public方法,若需应用于非public方法需启用AspectJ代理。同时,讨论了在同一类内部方法间调用时事务生效的情况,指出必须通过代理调用有事务注解的方法才能启动事务。还提到了异常处理与事务回滚的关系,以及方法中明确抛出异常对事务的影响。

@Transtaction注解是Spring提供的注解,那自然你在加上注解的类或方法上要被spring代理。

一、首先@Transtaction注解只能作用在public的方法或者类上,如果你的类或者方法是protected或者其他,虽然都不报错,但是注解都不生效。

如下,@Transaction注解是不会生效的,因为他的修饰符不是public

@Override
    @Transactional
    protected boolean a(){
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

注意:@Transactional 只能用于public 的方法上,否则事务会失效,如果要用在非 public 方法上,可以开启AspectJ 代理模式
 

二、现有a方法和b方法,首先他们在同一个类中,并且都被spring所管理

问此时,在a方法上和b方法上都加上了@Transtaction注解,事务是否会会回滚。我们执行的是a方法。

    @Transactional
    public boolean a(){
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

    @Transactional
    public int b() {
        System.out.println("进入b方法了");
        User user = new User();
        user.setPhone("12314");
        System.out.println("开始insert了");
        userMapper.insert(user);
        int i = 1/0;

        return 1;
    }

答案是会会回滚。

三、同样是上面的场景

但是a上不加@Transtaction注解,异常不管是在a方法出现还是b方法出现,事务都不会生效.

场景如下:

    @Override
    public boolean a(){
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

    @Override
    @Transactional
    public int b() {
        System.out.println("进入b方法了");
        User user = new User();
        user.setPhone("12314");
        System.out.println("开始insert了");
        userMapper.insert(user);
        int i = 1/0;               

        return 1;
    }

原因如下:

spring 在扫描bean的时候会扫描方法上是否包含@Transactional 事务注解,如果包含,则 spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean 。

当这个有事务注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会开启事务(transaction) 。

但是,如果先调用一个没有事务的方法,然通这个方法再去有事务,由于该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是 @Transactional 注解无效。

四、现有a方法和b方法,首先他们在同一个类中,并且都被spring所管理

a方法和b方法上都加上@Transaction,但是我们异常在b中被捕获或者在a中被捕获,事务都不会生效。 但是你不在a方法或者b方法中捕获,你只在调用a方法的地方捕获异常,异常会回滚.

如下:

@Override
    @Transactional
    public boolean a(){
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

    @Override
    @Transactional
    public int b() {
        System.out.println("进入b方法了");
        User user = new User();
        user.setPhone("12314");
        System.out.println("开始insert了");
        userMapper.insert(user);
//        int i = 1/0;
        try {
            int i = 1/0;
        }catch (Exception e){
            e.printStackTrace();
        }

        return 1;
    }

但是你只是在controller调用这段代码,事务会回滚。

如下:

@Override
    @Transactional
    public boolean a(){
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

    @Override
    @Transactional
    public int b() {
        System.out.println("进入b方法了");
        User user = new User();
        user.setPhone("12314");
        System.out.println("开始insert了");
        userMapper.insert(user);
        int i = 1/0;

        return 1;
    }


调用 a的地方
@Test
    public void test111() {
        try {
            userService.a();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

五、在方法上throws 抛出异常,事务依旧会回滚

@Override
    @Transactional
    public boolean a() throws  Exception{
        System.out.println("开始调用b方法了");
        b();
        System.out.println("b方法完成了");
        return false;
    }

    @Override
    @Transactional
    public int b() throws  Exception{
        System.out.println("进入b方法了");
        User user = new User();
        user.setPhone("12314");
        System.out.println("开始insert了");
        userMapper.insert(user);
        int i = 1/0;


        return 1;
    }


     @Test
    public void test111() throws Exception {
        userService.a();
    }

简单总结:

首先@Transaction注解 作用的方法上,必须要要被spring代理,@Transaction注解只能作用在public方法上,如果硬要作用在非public方法上,可以使用Aspect J 代理。

### Spring @Transactional 注解 使用指南与常见问题 #### 1. @Transactional 注解的基本使用 @Transactional 注解Spring 框架中用于声明式事务管理的核心注解。它可以通过简单的配置实现对方法的事务控制,而无需编写复杂的事务管理代码。该注解可以应用于类或方法级别[^2]。 - **类级别**:当 @Transactional 应用于类时,类中的所有公共方法都将被事务管理。 - **方法级别**:推荐在方法上使用 @Transactional,以实现更细粒度的事务控制。 ```java @Service public class OrderService { @Transactional public void createOrder() { // 业务逻辑 } } ``` #### 2. 注意点:@Transactional 只能作用于公共方法 @Transactional 注解只能作用于公共方法。如果将该注解应用于私有或受保护的方法,则 Spring AOP 无法检测到这些注解,从而导致事务不起作用[^2]。 ```java // 错误示例:私有方法上的 @Transactional 不起作用 private @Transactional void updateAccount() { // 更新账户逻辑 } ``` #### 3. 自调用问题及其解决方案 在同一类中,如果一个非事务方法调用了带有 @Transactional 注解的另一个方法,事务将不会生效。这是因为 Spring AOP 使用代理机制,只有通过代理对象调用的方法才会被事务管理[^3]。 **解决方法**: - 使用 AspectJ 取代 Spring AOP 代理,以解决自调用问题[^1]。 - 或者通过显式注入当前 Bean 的代理实例来调用目标方法。 ```java @Service public class OrderService { @Autowired private OrderService self; private void insert() { self.insertOrder(); // 通过代理对象调用 } @Transactional public void insertOrder() { // 插入订单逻辑 } } ``` #### 4. 事务边界的问题 Spring AOP 在事务管理中仅检查首次进入 @Autowired 代码时的注解状态。如果一个未标注 @Transactional 的方法调用了另一个标注了 @Transactional 的方法,后者将被忽略[^2]。 ```java // 错误示例:事务边界未正确创建 public void processOrder() { saveOrder(); // 此处没有事务 } @Transactional public void saveOrder() { // 保存订单逻辑 } ``` #### 5. 编程式事务管理:TransactionTemplate 对于需要动态或复杂事务逻辑的场景,可以使用 TransactionTemplate 进行编程式事务管理[^4]。 - **execute 方法**:执行包含事务的代码块,并支持返回值。 - **executeWithoutResult 方法**:执行无返回值的事务操作。 ```java @Autowired private TransactionTemplate transactionTemplate; public User createUser(User user) { return transactionTemplate.execute(status -> { try { User newUser = userDao.save(user); return newUser; } catch (DataAccessException e) { status.setRollbackOnly(); throw new ServiceException("保存用户失败", e); } }); } ``` #### 6. DAO 层事务管理 在 DAO 层使用 @Transactional 注解时,通常需要抛出异常以触发事务回滚。例如,在 BaseDaoImpl 中,save、update 和 delete 方法均可能抛出 Exception[^5]。 ```java @Transactional public Object save(Object entity) throws Exception { getSession().save(entity); return entity; } ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值