问题
上一话,我们发现mysql确实不支持DDL事务(截至到mysql8.0)。
但是业务需求上存在呢?该怎么解决呢?
有个业务场景是这样的,通过用户的配置同步修改表结构(DDL)和业务元数据(DML)。
处理思路
- 事务传播行为:不要放在一个事务里面!
业务代码 TransactionalDefinition.PROPAGATION_REQUIRED
DDL处理代码是 propagation = Propagation.REQUIRES_NEW
业务代码包含DDL处理
当DDL处理异常时,业务代码也异常回滚。
- 持久化的顺序:DML 、DDL (DDL放在最后处理)
如果顺序是DDL、DML。当DDL执行成功、DML执行失败回滚时,DDL并没有回滚语句。从业务整体上,并没有达到全部回滚的效果。
代码
业务
@Override
// Propagation.REQUIRED 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务。该设置是默认值。
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public BaseResult config(BusinessConfigDTO dto) throws Exception {
// 略。业务处理
// DML
persistenceBusinessConfig(dto);
// DDL tables是前面处理好的最后要执行的DDL的封装
tableUtil.executeBatch(tables);
return new BaseResult();
}
DDL
// Propagation.REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public void executeBatch(List<TableDto> tableDtos){
String sql = tableDtos.stream().map(e -> {
// return ...;处理生成sql
}).collect(Collectors.joining(";"));
ddlMapper.execute(sql);
}