Spring的事务隔离级别等不介绍了
在Spring的事务应用中,有时候需要用到循环体内单个控制事务,每一次循环与上次循环不交叉影响,单独提交或回滚,不影响整个循环体。
//开启事务
@Transactional(propagation = Propagation.REQUIRED)
public Result generateMeteringMonthlyBill() {
Result ret = Result.success();
GenerateContractBillService billService = BillServiceGenerateFactory.getMeteringMonthlyBillService();
List<ServiceContractDTO> contractList = billService.getContractList();
for(ServiceContractDTO dto:contractList){
try {
//单独事务,每次回滚或提交不影响,调用方法的事务(generateMeteringMonthlyBill),也不影响下次循环的事务
billService.processContract(dto,endDate);
} catch (Exception e) {
//调用日志服务,单独事务
sysLogService.addSysLog("", "", dto.getServicectrCode(), "T03", "", "计量月结合同生成账单失败-异常:" + e.getMessage());
e.printStackTrace();
}
}
return ret;
}
由于Spring的事务传播级别是类级别,如果类中的一个方法使用的某一个类型的事务,那么整个类的事务都是一种事务,而且回滚级别也是类级别的,也就是在同一个类中A方法调用B方法,A方法使用REQUIRED,B方法使用的REQUIRES_NEW,在B方法抛出RUNTIMEException,在A方法中捕获,回滚点不是到B方法,而是B方法不进行回滚,因为Spring事务认定级别以类为单位,所以只有退出类的调用时,对会触发事务的提交或回滚。所以即使在同个类中调用不同的事务级别,也是没有意义的。因为Spring 事务代理类执行方法的切入点是类:
Spring 代理执行方法(1):
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
**final String joinpointIdentification = methodIdentification(method, targetClass);**
执行(2) targetClass不会为NULL:
protected String methodIdentification(Method method, Class<?> targetClass) {
return (targetClass != null ? targetClass : method.getDeclaringClass()).getName() + "." + method.getName();
}
鉴于这个原因,解决方法需要在循环体内的进行单独事务控制的方法,放在一个A类中,包含循环体的方法放在一个B类中,这个A类中方法使用REQUIRES_NEW事务控制,B类使用REQUIRED事务控制。这样就解决了循环体内的相互影响