【Spring】@Transactional 闲聊
2021-05-05 13:29
标签:prot port utils odi sse from 的区别 ann resources 菜瓜:上次的AOP理论知识看完收获挺多的,虽然有一个自定义注解的demo,但还是觉得差点东西 水稻:我也觉得没有跟一遍源码还是差点意思,这次结合@Transactional注解深入源码看一下 菜瓜:事务注解,这个平时用的挺多的 水稻:是吗?来看看你的基础咋样 菜瓜:虽然没看过源码,我大胆猜测一下 水稻:可以啊,平时的代码没白写 菜瓜:coding这种事情,easy啦! 水稻:这就飘了?来看这个问题 菜瓜:。。。这不就是大事务嵌套小事务嘛。。。我不会 水稻:不扯了,来看源码吧,这个问题等解释了传播属性你就知道了 菜瓜:懂,接下来的代码逻辑就是在增强类TransactionInterceptor的invoke方法里 水稻:对 菜瓜:这就是传播属性NESTED?默认的是REQUIRED,还有一个常用的REQUIRES_NEW呢? 水稻:搞清楚这个其实从数据库连接入手其实就很清楚 菜瓜:传播属性了解。回滚的问题还得再看看,篇幅很大是很复杂吗? 水稻:其实不复杂,就是要跟踪源码断点调试。。。截图搞来搞去,篇幅就很长,你自己去调的话其实很快 菜瓜:那我下去康康 总结 【Spring】@Transactional 闲聊 标签:prot port utils odi sse from 的区别 ann resources 原文地址:https://www.cnblogs.com/nightOfStreet/p/13192214.html
/**
* @author QuCheng on 2020/6/24.
*/
@Service
public class ItemServiceImpl implements ItemService {
@Resource
private IcbcItemMapper itemMapper;
@Resource
private ItemService itemService;
@Override
public void changeNameById(Long itemId) {
// changeItemById(itemId);
itemService.changeItemById(itemId);
}
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void changeItemById(Long itemId) {
itemMapper.updateNameById(itemId, "name4");
int a = 10 / 0;
itemMapper.updatePriceById(itemId, 100L);
}
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector
// 增强
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
} public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
。。。
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport‘s invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
。。。
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,
final InvocationCallback invocation) throws Throwable {
。。。
// ①创建事务,数据库连接处理也在这
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 调用目标方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 异常后事务处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
。。。
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
。。。
// 如果连接是新的,就进行绑定
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
}
。。。
}
class TransactionSynchronizationManager
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void changeNameById(Long itemId) {
itemMapper.updateNameById(itemId, "A");
try {
itemService.changeItemById(itemId);
// itemService.changeItemByIdNested(itemId);
} catch (Exception e) {
System.out.println("我想继续执行,不影响修改A");
}
itemMapper.updatePriceById(itemId, 1L);
}
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void changeItemById(Long itemId) {
itemMapper.updateNameById(itemId, "B+REQUIRED");
itemMapper.updatePriceById(itemId, 10L);
int a = 10 / 0;
}
@Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.NESTED)
@Override
public void changeItemByIdNested(Long itemId) {
itemMapper.updateNameById(itemId, "B+NESTED");
itemMapper.updatePriceById(itemId, 100L);
int a = 10 / 0;
}
-- 测试结果
//① itemService.changeItemById(itemId); 数据库所有数据都不会改变
我想继续执行,不影响修改A
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
// ② itemService.changeItemByIdNested(itemId); 第一个方法的修改会生效
我想继续执行,不影响修改A