mysql的引擎常用的有两个,一个MyISAM,另一个是InnoDB,mysql默认的为MyISAM,而InnoDB才是支持事务的。所以一般需要修改下,如何修改就不说了。
事务需要依赖数据库,好久没使用声明式事务,今天试了下。关键配置如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<
tx:advice
id="transactionAdvice" transaction-manager="transactionManager">
<
tx:attributes
>
<
tx:method
name="add*" propagation="REQUIRED" />
<
tx:method
name="append*" propagation="REQUIRED" />
<
tx:method
name="insert*" propagation="REQUIRED" />
<
tx:method
name="save*" propagation="REQUIRED" />
<
tx:method
name="update*" propagation="REQUIRED" />
<
tx:method
name="modify*" propagation="REQUIRED" />
<
tx:method
name="edit*" propagation="REQUIRED" />
<
tx:method
name="delete*" propagation="REQUIRED" />
<
tx:method
name="remove*" propagation="REQUIRED" />
<
tx:method
name="tx*" propagation="REQUIRED" />
<
tx:method
name="repair" propagation="REQUIRED" />
<
tx:method
name="delAndRepair" propagation="REQUIRED" />
<
tx:method
name="get*" propagation="SUPPORTS" />
<
tx:method
name="find*" propagation="SUPPORTS" />
<
tx:method
name="load*" propagation="SUPPORTS" />
<
tx:method
name="search*" propagation="SUPPORTS" />
<
tx:method
name="datagrid*" propagation="SUPPORTS" />
<
tx:method
name="*" propagation="SUPPORTS" />
</
tx:attributes
>
</
tx:advice
>
<
aop:config
>
<
aop:pointcut
id="transactionPointcut" expression="execution(* com.wondersgroup.employeeBenefits.*.*.service..*Impl.*(..))" />
<!-- com.wondersgroup.benefit.*.core.service..*Impl.*(..) -->
<
aop:advisor
pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</
aop:config
>
|
事务配置好之后再service中手动抛了个exception,结果没有回滚,service方法如下
1
2
3
4
5
6
7
8
9
|
@Override
public
int
saveBudgetApplyInfo(BudgetApplyInfo budgetApplyInfo)
throws
Exception {
budgetApplyInfoMapper.insert(budgetApplyInfo);
if
(
1
==
1
){
throw
new
Exception();
}
return
1
;
}
|
跟着断点一步步进去查看原因
在
TransactionAspectSupport中发现这样一个方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
/**
* Handle a throwable, completing the transaction.
* We may commit or roll back, depending on the configuration.
* @param txInfo information about the current transaction
* @param ex throwable encountered
*/
protected
void
completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
if
(txInfo !=
null
&& txInfo.hasTransaction()) {
if
(logger.isTraceEnabled()) {
logger.trace(
"Completing transaction for ["
+ txInfo.getJoinpointIdentification() +
"] after exception: "
+ ex);
}
if
(txInfo.transactionAttribute.rollbackOn(ex)) {
try
{
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch
(TransactionSystemException ex2) {
logger.error(
"Application exception overridden by rollback exception"
, ex);
ex2.initApplicationException(ex);
throw
ex2;
}
catch
(RuntimeException ex2) {
logger.error(
"Application exception overridden by rollback exception"
, ex);
throw
ex2;
}
catch
(Error err) {
logger.error(
"Application exception overridden by rollback error"
, ex);
throw
err;
}
}
else
{
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try
{
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch
(TransactionSystemException ex2) {
logger.error(
"Application exception overridden by commit exception"
, ex);
ex2.initApplicationException(ex);
throw
ex2;
}
catch
(RuntimeException ex2) {
logger.error(
"Application exception overridden by commit exception"
, ex);
throw
ex2;
}
catch
(Error err) {
logger.error(
"Application exception overridden by commit error"
, ex);
throw
err;
}
}
}
}
|
上面的方法中有这么一段
1
|
txInfo.transactionAttribute.rollbackOn(ex),这里是判断是否需要执行回滚操作的,跟踪rollbackOn方法最后会执行到
|
DefaultTransactionAttribute中的rollbackOn方法
1
2
3
4
5
6
7
8
|
/**
* The default behavior is as with EJB: rollback on unchecked exception.
* Additionally attempt to rollback on Error.
* <p>This is consistent with TransactionTemplate's default behavior.
*/
public
boolean
rollbackOn(Throwable ex) {
return
(ex
instanceof
RuntimeException || ex
instanceof
Error);
}
|
看到这里,应该都清楚了。。。自己主动抛异常Exception是不对的。这里只捕获运行时异常
1
|
RuntimeException 及Error,所以我们测试时不可以直接抛Exception,而应该换成
|
1
|
RuntimeException 。当然。也可在xml中指定rollback-
for
|
1
|
<
tx:method
name="add*" propagation="REQUIRED" rollback-for="Exception" />
|