事务 特性 深入学习
事务的特性ACID
事务隔离级别
事务传播属性
1.方法内部调用
事务不生效,A->B相当于把B的代码移动到A里,不管哪个方法抛异常,都不会入库成功,因为用的是A的事务
注: 若想神效,有两种方式
a. 用ApplicationContextUtil从spring ioc容器中获取代理bean 调用
b.用AopContext.currentProxy 获取bean进行调用,此时也是代理bean
注意:此处需开启 @EnableAspectJAutoProxy(exposeProxy=true)
2.内部方法外部调用
事务生效,A->B 根据不同的隔离级别,产生不同的结果
场景如下:
方法A(saveBatch)和方法B(savePrice)在同一个service中
方法A | 方法B**(抛异常)** | A入库结果 | B入库结果 | |
---|---|---|---|---|
场景一 | 无事务 | 无事务 | 成功 | 成功 |
场景二 | 无事务 | required | 成功 | 失败 |
场景三 | required | 无事务 | 失败 | 失败 |
场景四 | required | not_supported | 失败 | 成功 |
场景五 | required | requires_new | 失败 | 失败 |
场景六 | required | required | 失败 | 失败 |
场景七 | required | nerver | 失败 | 失败 |
场景八 | required | mandatory | 失败 | 失败 |
事务底层原理
同一个事务内,满足如下条件才属于同一个事务:
1.同一个连接
2.自动提交为false
3.执行提交或者回滚
代码
package com.example.demo1.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo1.entity.TestBatch;
import com.example.demo1.entity.TestPrice;
import com.example.demo1.mapper.TestBatchMapper;
import com.example.demo1.service.TestBatchService;
import com.example.demo1.service.TestPriceService;
import com.example.demo1.util.ApplicationContextUtil;
import java.math.BigDecimal;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* <p>
* 服务实现类
* </p>
*
* @author lucas
* @since 2020-04-08
*
* 1.方法内部调用,事务不生效,A->B 相当于把B的代码块移动到A方法里
* 2.方法内部调用,可以使用applicationContext和AopCOntext两种方式获取代理bean
*
*
*/
@Service
@Slf4j
public class TestBatchServiceImpl extends ServiceImpl<TestBatchMapper, TestBatch> implements
TestBatchService {
@Resource
private TestPriceService testPriceService;
@Override
public void loadTestBatch(String fileName) {
super.baseMapper.loadTestBatch(fileName);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void saveBatch(TestBatch testBatch) {
getBaseMapper().insert(testBatch);
TestPrice testPrice = TestPrice.builder().type("www").money(BigDecimal.ONE).comid(123L)
.price(BigDecimal.TEN).build();
//1. 事务不生效,不管A方法还是B方法抛异常,若不捕获,数据均不入库,若捕获,则均入库
//this.savePrice(testPrice);
//2. 事务生效,此时使用代理对象
((TestBatchServiceImpl) ApplicationContextUtil.getBean("testBatchServiceImpl")).savePrice(testPrice);
/*
((TestBatchServiceImpl) AopContext.currentProxy()).savePrice(testPrice);
*/
/*throw new RuntimeException();*/
}
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void savePrice(TestPrice testPrice) {
testPriceService.saveTestPrice(testPrice);
throw new RuntimeException();
}
@Override
public void isolation() {
}
}
ceService.saveTestPrice(testPrice);
throw new RuntimeException();
}
@Override
public void isolation() {
}
}