- 浏览: 45955 次
- 性别:
- 来自: 深圳
最新评论
还有一点需要说明的是,AService的方法在执行之前创建的transactionstatus确实是通过这个方法创建的,但是,BService的方法在执行之前创建transactionstatus的方法就与这个不一样了,下面会有详解。
回顾了事务开始时所调用的方法之后,是不是觉得现在对spring如何处理事务越来越清晰了呢。由于这么几个方法的调用,每个方法入栈之前它的事务状态就已经被设置好了。这个事务状态就是为了在方法出栈时被调用而准备的。
让我们再次回到BService中的方法出栈的那个时间段,看看spring都做了些什么,我们知道,后入栈的肯定是先出栈,BService中的方法后入栈,拿它肯定要先出栈了,它出栈的时候是要判断是否要提交事务,释放资源的,让我们来看看TransactionInterceptor的invoke的最后那个方法doCommitTransactionAfterReturning:
代码
1. protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {
2. if (txInfo != null && txInfo.hasTransaction()) {
3. if (logger.isDebugEnabled()) {
4. logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());
5. }
6. this.transactionManager.commit(txInfo.getTransactionStatus()); //瞧:提交事务时用到了表明事务状态的那个TransactionStatus对象了。
7. }
8. }
看这个方法的名字就知道spring是要在业务方法出栈时提交事务,貌似很简单,但是事实是这样的吗? 我们接着往下看。
代码
1. public final void commit(TransactionStatus status) throws TransactionException {
2. DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
3.
4. if (defStatus.isCompleted()) {
5. throw new IllegalTransactionStateException(
6. "Transaction is already completed - do not call commit or rollback more than once per transaction");
7. }
8. if (defStatus.isLocalRollbackOnly()) {
9. if (defStatus.isDebug()) {
10. logger.debug("Transactional code has requested rollback");
11. }
12. processRollback(defStatus);
13. return;
14. }
15. if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
16. if (defStatus.isDebug()) {
17. logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
18. }
19. processRollback(defStatus);
20. throw new UnexpectedRollbackException(
21. "Transaction has been rolled back because it has been marked as rollback-only");
22. }
23.
24. processCommit(defStatus);
25. }
上面这段代码就是transactionmanager中的commit,但是看上去,它又把自己的职责分配给别人了,从代码里我们看到,如果事务已经结束了就抛异常,如果事务是rollbackonly的,那么就rollback吧,但是按照正常流程,我们还是想来看一下,事务的提交,就是processCommit(status)这个方法吧。
代码
1. private void processCommit(DefaultTransactionStatus status) throws TransactionException {
2. try {
3. boolean beforeCompletionInvoked = false;
4. try {
5. triggerBeforeCommit(status);
6. triggerBeforeCompletion(status);
7. beforeCompletionInvoked = true;
8. if (status.hasSavepoint()) {
9. if (status.isDebug()) {
10. logger.debug("Releasing transaction savepoint");
11. }
12. status.releaseHeldSavepoint();
13. }
14. else if (status.isNewTransaction()) {//这个判断非常重要,下面会详细讲解这个判断的作用
15. if (status.isDebug()) {
16. logger.debug("Initiating transaction commit");
17. }
18. boolean globalRollbackOnly = status.isGlobalRollbackOnly();
19. doCommit(status); //提交事务
20. // Throw UnexpectedRollbackException if we have a global rollback-only
21. // marker but still didn't get a corresponding exception from commit.
22. `````````````````````
23. finally {
24. cleanupAfterCompletion(status);//关闭session
25. }
26. }
protected void doCommit(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Committing Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
}
try {
txObject.getSessionHolder().getTransaction().commit();//提交事务
}
.......
}
我们注意到,在判断一个事务是否是新事务之前还有一个status.hasSavepoint()的判断,我认为这个判断事实上就是嵌套事务的判断,即判断这个事务是否是嵌套事务,如果不是嵌套事务,则再判断它是否是一个新事务,下面这段话就非常重要了,BService的中的方法是先出栈的,也就是说在调用BService之前的创建的那个事务状态对象在这里要先被判断,但是由于在调用BService的方法之前已经创建了一个Transaction和Session(假设我们使用的是hibernate3),这时候在创建第二个TransactionInfo(再强调一下吧,TransactionInfo并不是Transaction,Transaction是真正的事务对象,TransactionInfo只不过是一个辅助类而已,用来记录一系列状态的辅助类)的TransactionStatus的时候就会进入下面这个方法(当然在这之前会判断一下当前线程中是否已经有了一个SessionHolder对象,不清楚SessionHolder作用的同学情况第一篇文章),这个方法其实应该放到第一篇文章中讲的,但是想到如果不讲事务提交就讲这个方法好像没有这么贴切,废话少说,我们来看一下吧:
代码
1. private TransactionStatus handleExistingTransaction(
2. TransactionDefinition definition, Object transaction, boolean debugEnabled)
3. throws TransactionException {
4.
5. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
6. throw new IllegalTransactionStateException(
7. "Transaction propagation 'never' but existing transaction found");
8. }
9.
10. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
11. if (debugEnabled) {
12. logger.debug("Suspending current transaction");
13. }
14. Object suspendedResources = suspend(transaction);
15. boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);
16. return newTransactionStatus(
17. definition, null, false, newSynchronization, debugEnabled, suspendedResources);
18. }
19.
20. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
21. if (debugEnabled) {
22. logger.debug("Suspending current transaction, creating new transaction with name [" +
23. definition.getName() + "]");
24. }
25. Object suspendedResources = suspend(transaction);
26. doBegin(transaction, definition);
27. boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
28. return newTransactionStatus(
29. definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
30. }
31.
32. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
33. if (!isNestedTransactionAllowed()) {
34. throw new NestedTransactionNotSupportedException(
35. "Transaction manager does not allow nested transactions by default - " +
36. "specify 'nestedTransactionAllowed' property with value 'true'");
37. }
38. if (debugEnabled) {
39. logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
40. }
41. if (useSavepointForNestedTransaction()) {
42. // Create savepoint within existing Spring-managed transaction,
43. // through the SavepointManager API implemented by TransactionStatus.
44. // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
45. DefaultTransactionStatus status =
46. newTransactionStatus(definition, transaction, false, false, debugEnabled, null);
47. status.createAndHoldSavepoint();
48. return status;
49. }
50. else {
51. // Nested transaction through nested begin and commit/rollback calls.
52. // Usually only for JTA: Spring synchronization might get activated here
53. // in case of a pre-existing JTA transaction.
54. doBegin(transaction, definition);
55. boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
56. return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
57. }
58. }
59.
60. // Assumably PROPAGATION_SUPPORTS.
61. if (debugEnabled) {
62. logger.debug("Participating in existing transaction");
63. }
64. boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
65. return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
66. }
我们看到这个方法其实很明了,就是什么样的传播途径就创建什么样的transactionstatus,这个方法是在事务开始时被调用的,拿到我们之前举的例子中来看下,我们就恍然大悟了,原来,如果之前已经创建过事务,那个这个新建的transactionstauts就不应该是属于一个newTransaction了,所以第3个参数就是false了。
也就是说,在BService的方法出栈要要执行processcommit,但是由于BService的那个TransactionStatus不是一个newTransaction,所以它根本不会触发这个动作:
代码
1. else if (status.isNewTransaction()) {//这个判断非常重要,下面会详细讲解这个判断的作用
2. if (status.isDebug()) {
3. logger.debug("Initiating transaction commit");
4. }
5. boolean globalRollbackOnly = status.isGlobalRollbackOnly();
6. doCommit(status);
7. }
也就是说在BService的方法出栈后,事务是不会提交的。这完全符合propragation_required的模型。 而在AService的方法出栈后,AService的方法所对应的那个TransactionStatus对象的newTransaction属性是为true的,即它会触发上面这段代码,进行真正的事务提交。让我们回想一下AService方法入栈之前创建TransactionStatus对象的情形吧:
newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);看到第3个参数为true没有。 那么事务该提交了吧,事务的提交我想使用过hibernate的人都知道怎么提交了:
txObject.getSessionHolder().getTransaction().commit();
从当前线程中拿到SessionHolder,再拿到开始事务的那个Transaction对象,然后再commit事务。在没有用spring之前,我们经常这么做。呵呵。
好吧,我已经说到了spring声明式事务管理的70%到80%的内容了,这70%到80%的内容看上去还是非常容易理解的,如果把这两篇文章认真看过,我相信会有所收获的,剩下的内容需要靠大家自己去挖掘了,因为另剩下的内容可是需要花费很多时间的,因为牵扯的东西实在是太多了,呵呵。最后祝大家阅读愉快,因为我的文笔实在是让大家的眼睛受罪了。
发表评论
-
Spring与Struts整合3种方式实例
2009-11-04 23:35 1077Spring与Struts整合3种方式实例 Sprin ... -
解惑 spring 嵌套事务
2009-10-26 14:58 1261在所有使用 spring 的应用中, 声明式事务管理可能是使用 ... -
Spring声明式事务管理源码解读(3)
2009-10-26 14:55 760上次说到spring声明式事 ... -
Spring声明式事务管理源码解读(2)
2009-10-26 14:52 760接着我们重点再回头看一下createTransactionIf ... -
Spring声明式事务管理源码解读(1)
2009-10-26 14:43 778/***作者:张荣华(ahuaxuan ... -
在Spring中如何使用加密外部属性文件
2009-10-19 12:40 1063在Spring的开发中, ... -
Spring 配置Spring数据源
2009-10-19 11:17 805不管通过何种持久化 ...
相关推荐
Spring源代码解析(六):Spring声明式事务处理.doc
Spring声明式事务配置管理方法
spring声明式事务实例 可复制修改使用。。。。。。。。。。
Spring框架的声明式事务管理是Java开发中的核心特性,它为高效且可靠的数据操作提供了强大支持。Spring通过@Transactional注解以及底层的AOP和代理机制实现了声明式事务。这个机制允许开发者通过简单的注解就能控制...
spring声明式事务管理异常处理的测试
spring声明式事务处理demo。myeclipse工程
Java高级编程 实验报告 spring 声明事务 实验目的 掌握spring 声明式事务管理配置 实验环境 本实验采用本实验采用的eclipse或者 Myeclpse开发工具。Spring 4.0以上 Jdk1.7以上、oracle/mysql。
示例代码 博文链接:https://awaken2012.iteye.com/blog/1728283
Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 ...
spring声明式事务管理+jdbc+连接池 包内为代码,下载可直接执行。 一直用s2sh,感觉hibernate不好用,所以写了一个spring声明式事务管理+jdbc+连接池。
Spring 声明式事务和Spring 编程式事务
spring3,hibernate4 配置声明式事务管理(annotation方式)
使用@Transactional注解时,可以通过参数配置事务详情: 5.2.2 基于Annotation方式的声明式事务 * * * * * * * * 声明式事务管理 如何实现Spring的声明式事务管理? 5.2 声明式事务管理 Spring的声明式事务管理可以...
4.掌握基于AOP的声明式事务编程 按照三层架构构建web项目,在业务层添加事务控制。 1.创建web project项目命名为aopweb 2.添加spring支持、hibernate支持 3.配置WEB-INF/applicationContext.xml提供基于AOP的声明...
spring声明式事务管理_入门
spring声明式事务管理+jdbc+连接池.zip
1. 基于Aspectj实现动态数据源...6. 实现事务内切换数据源(支持原生Spring声明式事务哟,仅此一家),并支持多数据源事务回滚(有了它除了跨服务的事务你需要考虑分布式事务,其他都不需要,极大的减少了系统的复杂程度)
Spring 的事务管理是 Spring 框架中一个比较重要的知识点,该知识点本身并不复杂,只是由于其比较灵活,导致初学者很难把握。本教程从基础知识开始,详细分析了 Spring 事务管理的使用方法,为读者理清思路。
Spring的声明式事务管理是采用AOP(Aspect-Oriented Programming,面向切面编程)实现的。在编程式事务管理中,各事务处理代码实际上是相似的,这就造成了代码重复;而且编程式事务管理会造成事务管理代码和被管理的...