1、 编程式事务
Spring 事务管理有两种方式:
编程式事务:通过编码方式实现事务;
声明式事务:基于AOP实现,如 @Transactional 声明式注解。
2、 实现原理
编程式事务基于TransactionTemplate实现,TransactionTemplate继承TransactionOperations接口
TransactionOperations提供有返回结果执行事务操作和无返回结果执行事务操作
TransactionOperations 默认实现 executeWithoutResult 方法
public interface TransactionOperations {
@Nullable
T execute(TransactionCallback action) throws TransactionException;
default void executeWithoutResult(Consumer action) throws TransactionException {
execute(status -> {
action.accept(status);
return null;
});
}
}
TransactionTemplate 实现 execute 方法
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {
@Nullable
private PlatformTransactionManager transactionManager;
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
@Nullable
public T execute(TransactionCallback action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
}
3、编程式事务例子
3.1 编程式事务带返回值
CarOrderReplaceSubmitServices 订单提交
@Service
public class CarOrderReplaceSubmitServices implements CarOrderSubmitServices {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private CarOrderDao carOrderDao;
@Override
public Integer submit(CarOrderSubmitReqDto reqDto) {
CarOrderEntity carOrderEntity = new CarOrderEntity();
carOrderEntity.setOrderNo(reqDto.getOrderNo());
carOrderEntity.setCarNo(reqDto.getCarNo());
Integer id = transactionTemplate.execute(transactionStatus -> {
// 执行数据库事务操作
carOrderDao.add(carOrderEntity);
Integer tempId = carOrderEntity.getId();
this.updateStock(carOrderEntity, 1);
return tempId;
});
return id;
}
@Override
public void updateStock(CarOrderEntity carOrderEntity, Integer stockCount) {
// 声明式事务注解事务依旧有效
carOrderDao.updateStockByCarNo(carOrderEntity.getCarNo(), stockCount);
}
}
CarOrderDaoImpl 实现库存更新
@Service
public class CarOrderDaoImpl extends
ServiceImpl implements
CarOrderDao {
@Override
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = {Exception.class,RuntimeException.class})
public boolean updateStockByCarNo(String carNo, Integer stockCount) {
CarOrderEntity carOrderEntity = new CarOrderEntity();
carOrderEntity.setStockCount(stockCount);
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CarOrderEntity::getCarNo, carNo);
return super.baseMapper.update(carOrderEntity, wrapper) > 0;
}
}
在更新库存时使用声明时事务注解,事务传播行为依然有效:
3.1.1 REQUIRED
submit方法: 事务传播行为 Propagation.REQUIRED
updateStockById方法: 事务传播行为 Propagation.REQUIRED
结论:在同1个事务内一起提交
原因:因为submit已经存在事务,所以使用同1个事务
3.1.2 REQUIRES_NEW
submit方法: 事务传播行为 Propagation.REQUIRED
updateStockById方法: 事务传播行为 Propagation.REQUIRES_NEW
结论:不在同1个事务内,updateStockById更新时会死锁,等待submit提交,造成相互等待
原因:REQUIRES_NEW模式新建事务,如果当前存在事务,把当前事务挂起
其他事务传播行为的实践见: Spring事务传播行为-声明式事务
3.2 编程式事务不带返回值
transactionTemplate.executeWithoutResult(t -> {
// 执行数据库事务操作
carOrderDao.add(carOrderEntity);
this.updateStock(carOrderEntity, 1);
});



