我们用Spring时很多时候都会用到他的声明式事务简单的在配置文件中进行一些规则配置利用Spring的AOP功能就能轻松搞定事务问题这里面就涉及到一个事务的传播属性问题【Propagation】他在TransactionDefinition接口中定义有兴趣可以看看src共有种选项可用
PROPAGATION_REQUIRED支持当前事务如果当前没有事务就新建一个事务这是最常见的选择
PROPAGATION_SUPPORTS支持当前事务如果当前没有事务就以非事务方式执行
PROPAGATION_MANDATORY支持当前事务如果当前没有事务就抛出异常
PROPAGATION_REQUIRES_NEW新建事务如果当前存在事务把当前事务挂起
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作如果当前存在事务就把当前事务挂起
PROPAGATION_NEVER以非事务方式执行如果当前存在事务则抛出异常
PROPAGATION_NESTED支持当前事务新增Savepoint点与当前事务同步提交或回滚
现在结合一个实例应用以上各种传播属性来进行说明首先声明两个beanServiceA和ServiceB其中ServiceB被引用
view plaincopy to clipboardprint?
ServiceA {
void methodA() {
thodB();
}
}
ServiceB {
void methodB() {
//
}
}
ServiceA {
void methodA() {
thodB();
}
}
ServiceB {
void methodB() {
//
}
} 接下来我们就一一分析下
PROPAGATION_REQUIRED
加入当前正要执行的事务不在另外一个事务里那么就起一个新的事务比如说thodB的事务级别定义为PROPAGATION_REQUIRED 那么由于执行thodA的时候 thodA已经起了事务这时调用thodBthodB看到自己已经运行在thodA 的事务内部就不再起新的事务而假如thodA运行的时候发现自己没有在事务中他就会为自己分配一个事务 这样在thodA或者在thodB内的任何地方出现异常事务都会被回滚即使thodB的事务已经被 提交但是thodA在接下来fail要回滚thodB也要回滚
PROPAGATION_SUPPORTS
如果当前在事务中即以事务的形式运行如果当前不再一个事务中那么就以非事务的形式运行
PROPAGATION_MANDATORY
必须在一个事务中运行也就是说他只能被一个父事务调用否则他就要抛出异常
PROPAGATION_REQUIRES_NEW
比如我们设计thodA的事务级别为PROPAGATION_REQUIREDthodB的事务级别为PROPAGATION_REQUIRES_NEW 那么当执行到thodB的时候thodA所在的事务就会挂起thodB会起一个新的事务等待thodB的事务完成以后 他才继续执行他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了因为thodB是新起一个事务那么就是存在 两个不同的事务如果thodB已经提交那么thodA失败回滚thodB是不会回滚的如果thodB失败回滚 如果他抛出的异常被thodA捕获thodA事务仍然可能提交
PROPAGATION_NOT_SUPPORTED
当前不支持事务比如thodA的事务级别是PROPAGATION_REQUIRED 而thodB的事务级别是PROPAGATION_NOT_SUPPORTED 那么当执行到thodB时thodA的事务挂起而他以非事务的状态运行完再继续thodA的事务
PROPAGATION_NEVER
不能在事务中运行假设thodA的事务级别是PROPAGATION_REQUIRED 而thodB的事务级别是PROPAGATION_NEVER 那么thodB就要抛出异常了
PROPAGATION_NESTED
理解Nested的关键是savepoint他与PROPAGATION_REQUIRES_NEW的区别是PROPAGATION_REQUIRES_NEW另起一个事务将会与他的父事务相互独立 而Nested的事务和他的父事务是相依的他的提交是要等和他的父事务一块提交的也就是说如果父事务最后回滚他也要回滚的 而Nested事务的好处也是他有一个savepoint
view plaincopy to clipboardprint?
ServiceA {
void methodA() {
try {
thodB();
} catch (Exception e) {
// 执行其他业务
thodC();
}
}
}
ServiceA {
void methodA() {
try {
thodB();
} catch (Exception e) {
// 执行其他业务
thodC();
}
}
}也就是说thodB失败回滚那么thodA会回滚到savepoint点上thodA可以选择另外一个分支比如 thodC继续执行来尝试完成自己的事务但是这个事务并没有在EJB标准中定义