数据库单体事务

1. 事务传播机制

PROPAGATION_REQUIRED默认传播机制如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务无父事务时:子事务作为独立事务执行;有父事务时:子事务中的操作串入父事务中执行,并且一起提交,一个操作失败全部回滚
PROPAGATION_SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行无父事务时:以非事务方式执行;有父事务时:加入父事务执行,等同于PROPAGATION_REQUIRED
PROPAGATION_MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常无父事务时:抛出异常;有父事务时:加入父事务执行,等同于PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW创建一个新的事务,如果当前存在事务,则把当前事务挂起无父事务时:子事务新建事务作为独立事务执行;有父事务时:子事务新建事务作为独立事务执行,独立提交;
NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起无父事务时:以非事务方式执行;有父事务时:挂起父事务,自己按照无事务方式运行;子事务自身无回滚,出现异常若向上抛,可能导致父事务回滚;父事务回滚时,不会影响子事务
NEVER以非事务方式运行,如果当前存在事务,则抛出异常无父事务时:以非事务方式执行;有父事务时:抛出异常(若不处理会导致父事务回滚)
NESTED如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行无父事务时:创建独立事务,等同于PROPAGATION_REQUIRED;有父事务时:嵌套在父事务之内;子事务依赖父事务:子事务于父事务提交时提交;父事务回滚,子事务也回滚。

2. 同类中A方法调用B方法

  • A方法有事务,B方法没事务
@Service
public class DaServiceImpl extends ServiceImpl<DaDao, Da> implements DaService {

    @Transactional
    @Override
    public void insertEntity() {
        Da da = new Da();
        da.setCode("测试1");
        da.setDrawingCode("图片地址1");
        this.save(da);
        updateEntity(da);
    }

    public void updateEntity(Da dd){
        dd.setDrawingCode("修改地址");
        this.updateById(dd);
        int sum =1/0;
    }
}

结论:在同一个方法中A和B在同一个事务内部,B没加事务但是有默认事务,B方法出现异常,会导致A也回滚

  • A方法有事务,B方法有事务
@Service
public class DaServiceImpl extends ServiceImpl<DaDao, Da> implements DaService {

    @Transactional
    @Override
    public void insertEntity() {
        Da da = new Da();
        da.setCode("测试1");
        da.setDrawingCode("图片地址1");
        this.save(da);
        updateEntity(da);
    }
    
	@Transactional
    public void updateEntity(Da dd){
        dd.setDrawingCode("修改地址");
        this.updateById(dd);
        int sum =1/0;
    }
}

结论:A和B在同一个事务内部,B只是增加一个事务注解,但是没有指定事务的传播机制,同上也是有默认的,B出现异常,A也会回滚

  • A方法有事务,B方法没有事务(B方法自己把异常捕捉了)
@Service
public class DaServiceImpl extends ServiceImpl<DaDao, Da> implements DaService {

    @Transactional
    @Override
    public void insertEntity() {
        Da da = new Da();
        da.setCode("测试1");
        da.setDrawingCode("图片地址1");
        this.save(da);
        updateEntity(da);
    }
    
	@Transactional
    public void updateEntity(Da dd){
        dd.setDrawingCode("修改地址");
        this.updateById(dd);
        try {
            int sum =1/0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结论:这个时候是会报错:A的事务是不会回滚的,因为在A方法认为是没有接收到异常的,B本身抛了一个位置异常被自己吃了,解决方法要么就手动回滚,要么就抛出runtimeException 及他的子类

@Transactional
    public void updateEntity(Da dd){
        dd.setDrawingCode("修改地址");
        this.updateById(dd);
        try {
            int sum =1/0;
        } catch (Exception e) {
             throw e;//抛出
        }
    }
@Transactional
    public void updateEntity(Da dd){
        dd.setDrawingCode("修改地址");
        this.updateById(dd);
        try {
            int sum =1/0;
        } catch (Exception e) {
           //手动回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
  • A方法没有事务,B方法有事务,用A去调用B,B出现异常,会回滚吗?
 public void A() {
        B();
    }

    @Transactional
    public void B(){
        //dd.setDrawingCode("修改地址");
        Da byId = this.getById("6881170a32c6b165f18b6f98137ca045");
        byId.setCode("测试");
        this.updateById(byId);

        int sum =1/0;

    }

结论:不会,因为事务的起始在A,A没有添加事务,也就是说,this.updateById(byId);这个代码是会执行到数据库的,且int sum =1/0;这句也会报错,就跟B没有任何事务一样

解决办法
1.使用代理(需要在主启动类上加上@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true))开启aop和代理

 public void A() {
         DaServiceImpl proxy = (DaServiceImpl) AopContext.currentProxy();
         proxy.B();
    }

    

2.自己注入自己


	@Autowired
    DaServiceImpl daService;
 public void A() {
         daService.B();
    }

    

这两种方法解决等同于A.B方法不在同一个类中,A(无事务)调用B(有事务)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值