美文网首页
StringBoot 事务失效

StringBoot 事务失效

作者: YUNDONG丶 | 来源:发表于2020-09-30 14:43 被阅读0次

事物失效的几种场景

  • <a href="#数据库不支持事务">数据库不支持事务</a>
  • <a href="#注解放在了私有方法上">注解放在了私有方法上</a>
  • <a href="#类内部调用">类内部调用</a>
  • <a href="#未捕获异常">未捕获异常</a>
  • <a href="#多线程场景">多线程场景</a>
  • <a href="#传播属性设置问题">传播属性设置问题</a>
<a id="数据库不支持事务">数据库不支持事务</a>

这个就不用多讲了,一般来说使用 MYSQL 的同学数据库引擎都默认使用 Innodb。如果你选用的是其他引擎如:MyISAM 数据库引擎就天然不支持事务。具体事项出门左转。

<a id="注解放在了私有方法上">注解放在了私有方法上</a>
public class UserService{
  /**
  * 根据用户名称获取用户姓名
  */
  @Transactional(rollbackFor = Exception.class)
  private String getUserNameByUserId(Long UserId){
    return "张三";
  }
}

总结: SpringBoot 的事务管理器不支持在私有方法上添加事务!

<a id="类内部调用">类内部调用</a>
// 事务生效
public class UserService{
  /**
  * 根据用户名称获取用户姓名
  */
  @Transactional(rollbackFor = Exception.class)
  public String getUserNameByUserId(Long userId){ 
    return getUserByUserId.getUserName();
  }
  
  public User getUserByUserId(Long userId){
    return new User();
  }
}
// 事务不生效
public class UserService{
  /**
  * 根据用户名称获取用户姓名
  */
  public String getUserNameByUserId(Long userId){ 
    return getUserByUserId.getUserName();
  }
  
  @Transactional(rollbackFor = Exception.class)
  public User getUserByUserId(Long userId){
    return new User();
  }
}

总结: 同一个类中两个方法相互调用,事务注解应该添加在入口的方法上。如:同一个一个类中 A 方法调用 B,那么注解就应该添加在 A 方法上,如果 B 方法调拨 A 那么注解就应该添加在 B 方法上

<a id="未捕获异常">未捕获异常</a>
public class UserService{
  /**
  * 根据用户名称获取用户姓名
  */
  @Transactional(rollbackFor = Exception.class)
  public String getUserNameByUserId(Long userId){ 
    try{
      return getUserByUserId.getUserName();
    }catch(Exception e){
    }
  }
}

总结: 异常不能自己捕捉,否则 SpringBoot 事务管理器就没法捕捉到异常。无法回滚。如果必须要添加异常捕捉一定要抛出异常

public class UserService{
  /**
  * 根据用户名称获取用户姓名
  */
  @Transactional(rollbackFor = Exception.class)
  public String getUserNameByUserId(Long userId){ 
    try{
      return getUserByUserId.getUserName();
    }catch(Exception e){
      throw new RuntimeException(); // 手动抛出异常
    }
  }
}
<a id="多线程场景">多线程场景</a>
package net.isyundong.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import net.isyundong.entity.A01;
import net.isyundong.entity.A02;
import net.isyundong.mapper.A01Mapper;
import net.isyundong.service.IA01Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;


@Service
public class A01ServiceImpl extends ServiceImpl<A01Mapper, A01> implements IA01Service {

    /**
     * 创建线程池
     */
    private static final ExecutorService threadPool = Executors.newFixedThreadPool(4);
        
    /**
     * 手动抛出异常判断用    
     */
    private static AtomicInteger ai = new AtomicInteger(1);

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private A02ServiceImpl a02Service;

 
    @Override
    public void multiThread() {
        // 用于记录事务
        List<TransactionStatus> transactionStatuss = Collections.synchronizedList(new ArrayList<TransactionStatus>());
        try {
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus transactionStatus = transactionManager.getTransaction(def);
            transactionStatuss.add(transactionStatus);
            A01 a1 = new A01();
            a1.setT01(randomString());
            save(a1);

            A02 a2 = new A02();
            a2.setT01(randomString());
            a02Service.save(a2);
        } catch (Exception e) {
            e.printStackTrace();
            for (TransactionStatus status : transactionStatuss) {
                status.setRollbackOnly();
            }
        }

        threadPool.execute(() -> {
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus transactionStatus = transactionManager.getTransaction(def);
            transactionStatuss.add(transactionStatus);

            try {
                A01 a111 = new A01();
                a111.setT01(randomString());
                save(a111);
                if (ai.incrementAndGet() % 3 == 0) {
                    int i = 0 / 0;
                }
            } catch (Exception e) {
                e.printStackTrace();
                for (TransactionStatus status : transactionStatuss) {
                    status.setRollbackOnly();
                }
            }
        });
    }

    public static String randomString() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 5).toUpperCase();
    }

}

<a id="传播属性设置问题">传播属性设置问题</a>
参数 解释
REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择
SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
MANDATORY 支持当前事务,如果当前没有事务,就抛出异常
REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
NESTED 支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事

个人博客

相关文章

  • StringBoot 事务失效

    事物失效的几种场景 数据库不支持事务 注解放在了私有方法上 类内部调用 未捕获异常 多线程场景 传播属性设置问题 ...

  • 事务相关的问题总结

    一、事务回滚问题 二、事务失效问题 三、事务失效的解决办法 方式一:自己手动创建事务,提交事务,回滚事务(Spri...

  • springboot事务失效解决-TransactionAspe

    事务失效解决 一 失效原因和写法(同一个类,controller调用有事务的方法) 一 事务生效解决(调用事务的...

  • 事务失效

    一.我碰到的事务失效的可能原因: (1)由于采用的是SpringMVC、 MyBatis,故统一采用了标注来声明S...

  • 锁库存,分布式事务

    分布式事务:网络问题+分布式机器 mysql默认级别可重复度 本地事务失效问题 同一个对象内事务方法互调默认失效,...

  • 内部调用引起Spring声明式事务@Transactional失

    失效的原因 Spring声明式事务是基于AOP生成的代理类来实现的,而AOP无法拦截内部调用,导致事务失效。 解决...

  • springboot事务失效

    事务不生效 访问权限问题众所周知,java的访问权限主要有四种:private、default、protected...

  • Spring事务什么时候会失效

    Spring事务什么时候会失效? Spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不...

  • AopContext.currentProxy()

    在同一个类中,非事务方法A调用事务方法B,事务失效,得采用AopContext.currentProxy().xx...

  • @Transactional注解事务失效总结

    情况一 同一类中无@Transactional事务方法调用有@Transactional注解的方法,事务失效。 分...

网友评论

      本文标题:StringBoot 事务失效

      本文链接:https://www.haomeiwen.com/subject/uvwuuktx.html