1.不指定rollbackFor
使用spring的声明式事务(即@Transactional注解)时,如果不指定rollbackFor,那么当程序发生Error时,事务将不会回滚!!!显然这将导致数据不一致!
如下述代码:
@Transactional
public void createXxx(final XxxCreateDTO dto) {
// 其它处理
......
xxxRepository.insertList(this.assembleItemList(dto));
}
spring官方解释如下:
2.捕获异常后,没有继续传递异常
如果事务方法捕获了异常,但是没有在catch块中继续抛出异常,那么该事务将不会回滚!!显然这将导致数据不一致!
@Transactional(rollbackFor = Exception.class)
public ResultDTO apply(XxxApplyModel applyModel) {
try {
return internalApply(applyModel);
} catch (Exception e) {
// 捕获异常后的一些处理,但是却没有继续抛出异常
......
}
}
}
正确的做法有两种:
- 在catch中抛出异常
@Transactional(rollbackFor = Exception.class)
public ResultDTO apply(XxxApplyModel applyModel) {
try {
return internalApply(applyModel);
} catch (Exception e) {
// 捕获异常后的一些处理,但是却没有继续抛出异常
......
throw e;
}
}
- 将事务的开启下沉到内部逻辑中,如本例中可以将事务的开启放到方法internalApply上
public ResultDTO apply(XxxApplyModel applyModel) {
try {
// 注意,要通过bean调用这个方法internalApply,不能通过this,
// 方法内部的调用不会开启事务
return internalApply(applyModel);
} catch (Exception e) {
// 捕获异常后的一些处理,但是却没有继续抛出异常
......
}
}
@Transactional(rollbackFor = Exception.class)
public FooDTO internalApply(XxxApplyModel applyModel) {
// business process
......
}
3.大事务问题
大事务,简单的说就是在一个事务中处理了很多其它耗时的操作,比如在事务中发起多个远程调用,耗时的校验逻辑放在了事务方法中等等,这会导致该事务的connection不能尽快释放,占用数据库资源,降低系统性能,如下面的方法:
@Transactional(rollbackFor = Exception.class)
public ResultDTO apply(ApplyDTO applyDTO) {
try {
// 条件校验
this.validateApply(applyDTO);
} catch (Exception e) {
return getApplyResultOnException(e, productNo);
}
// 业务处理 保存数据等操作
......
return buildApplyResult(productNo, null, null, true);
}
上述事务方法中校验逻辑validateApply是很耗时的,但是却放在了事务方法中,显然不合理。建议新加一个方法,依次调用apply方法和validateApply方法
public Foo applyXxx(ApplyDTO applyDTO) {
this.validateApply(applyDTO);
return apply(uniqueKey, applyDTO)
}