`
Feiing
  • 浏览: 242057 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

解惑 spring 嵌套事务

阅读更多
解惑 spring 嵌套事务

/**
  * @author 王政
  * @date 2006-11-24
  * @note 转载请注明出处
  */

   在所有使用 spring 的应用中, 声明式事务管理可能是使用率最高的功能了, 但是, 从我观察到的情况看,
绝大多数人并不能深刻理解事务声明中不同事务传播属性配置的的含义, 让我们来看一下 TransactionDefinition 接口中的定义

/**
	 * Support a current transaction, create a new one if none exists.
	 * Analogous to EJB transaction attribute of the same name.
	 * <p>This is typically the default setting of a transaction definition.
	 */
	int PROPAGATION_REQUIRED = 0;

	/**
	 * Support a current transaction, execute non-transactionally if none exists.
	 * Analogous to EJB transaction attribute of the same name.
	 * <p>Note: For transaction managers with transaction synchronization,
	 * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
	 * as it defines a transaction scopp that synchronization will apply for.
	 * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
	 * will be shared for the entire specified scope. Note that this depends on
	 * the actual synchronization configuration of the transaction manager.
	 * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
	 */
	int PROPAGATION_SUPPORTS = 1;

	/**
	 * Support a current transaction, throw an exception if none exists.
	 * Analogous to EJB transaction attribute of the same name.
	 */
	int PROPAGATION_MANDATORY = 2;

	/**
	 * Create a new transaction, suspend the current transaction if one exists.
	 * Analogous to EJB transaction attribute of the same name.
	 * <p>Note: Actual transaction suspension will not work on out-of-the-box
	 * on all transaction managers. This in particular applies to JtaTransactionManager,
	 * which requires the <code>javax.transaction.TransactionManager</code> to be
	 * made available it to it (which is server-specific in standard J2EE).
	 * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
	 */
	int PROPAGATION_REQUIRES_NEW = 3;

	/**
	 * Execute non-transactionally, suspend the current transaction if one exists.
	 * Analogous to EJB transaction attribute of the same name.
	 * <p>Note: Actual transaction suspension will not work on out-of-the-box
	 * on all transaction managers. This in particular applies to JtaTransactionManager,
	 * which requires the <code>javax.transaction.TransactionManager</code> to be
	 * made available it to it (which is server-specific in standard J2EE).
	 * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
	 */
	int PROPAGATION_NOT_SUPPORTED = 4;

	/**
	 * Execute non-transactionally, throw an exception if a transaction exists.
	 * Analogous to EJB transaction attribute of the same name.
	 */
	int PROPAGATION_NEVER = 5;

	/**
	 * Execute within a nested transaction if a current transaction exists,
	 * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
	 * <p>Note: Actual creation of a nested transaction will only work on specific
	 * transaction managers. Out of the box, this only applies to the JDBC
	 * DataSourceTransactionManager when working on a JDBC 3.0 driver.
	 * Some JTA providers might support nested transactions as well.
	 * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
	 */
	int PROPAGATION_NESTED = 6;


我们可以看到, 在 spring 中一共定义了六种事务传播属性, 如果你觉得看起来不够直观, 那么我来转贴一个满大街都有的翻译

引用

PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)


在我所见过的误解中, 最常见的是下面这种:

引用

假如有两个业务接口 ServiceA 和 ServiceB, 其中 ServiceA 中有一个方法实现如下

/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
// 调用 ServiceB 的方法
ServiceB.methodB();
}

那么如果 ServiceB 的 methodB  如果配置了事务, 就必须配置为 PROPAGATION_NESTED


这种想法可能害了不少人, 认为 Service 之间应该避免互相调用, 其实根本不用担心这点,PROPAGATION_REQUIRED 已经说得很明白,
如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务,就新建一个事务, 所以 ServiceB#methodB() 的事务只要遵循最普通的规则配置为 PROPAGATION_REQUIRED 即可, 如果 ServiceB#methodB (我们称之为内部事务, 为下文打下基础) 抛了异常, 那么 ServiceA#methodA(我们称之为外部事务) 如果没有特殊配置此异常时事务提交 (即 +MyCheckedException的用法), 那么整个事务是一定要 rollback 的, 什么 Service 只能调 Dao 之类的言论纯属无稽之谈, spring 只负责配置了事务属性方法的拦截, 它怎么知道你这个方法是在 Service 还是 Dao 里 ?

     说了这么半天, 那到底什么是真正的事务嵌套呢, 解释之前我们来看一下  Juergen Hoeller 的原话

Juergen Hoeller 写道

PROPAGATION_REQUIRES_NEW starts a new, independent "inner" transaction for the given scope. This transaction will be committed or rolled back completely independent from the outer transaction, having its own isolation scope, its own set of locks, etc. The outer transaction will get suspended at the beginning of the inner one, and resumed once the inner one has completed.

Such independent inner transactions are for example used for id generation through manual sequences, where the access to the sequence table should happen in its own transactions, to keep the lock there as short as possible. The goal there is to avoid tying the sequence locks to the (potentially much longer running) outer transaction, with the sequence lock not getting released before completion of the outer transaction.

PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.

Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction.

For example, consider parsing a very large input file consisting of account transfer blocks: The entire file should essentially be parsed within one transaction, with one single commit at the end. But if a block fails, its transfers need to be rolled back, writing a failure marker somewhere. You could either start over the entire transaction every time a block fails, remembering which blocks to skip - or you mark each block as a nested transaction, only rolling back that specific set of operations, keeping the previous work of the outer transaction. The latter is of course much more efficient, in particular when a block at the end of the file fails.


Juergen Hoeller 写道

Rolling back the entire transaction is the choice of the demarcation code/config that started the outer transaction.

So if an inner transaction throws an exception and is supposed to be rolled back (according to the rollback rules), the transaction will get rolled back to the savepoint taken at the start of the inner transaction. The immediate calling code can then decide to catch the exception and proceed down some other path within the outer transaction.

If the code that called the inner transaction lets the exception propagate up the call chain, the exception will eventually reach the demarcation code of the outer transaction. At that point, the rollback rules of the outer transaction decide whether to trigger a rollback. That would be a rollback of the entire outer transaction then.

So essentially, it depends on your exception handling. If you catch the exception thrown by the inner transaction, you can proceed down some other path within the outer transaction. If you let the exception propagate up the call chain, it's eventually gonna cause a rollback of the entire outer transaction.


    也就是说, 最容易弄混淆的其实是 PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED, 那么这两种方式又有何区别呢? 我简单的翻译一下 Juergen Hoeller 的话 :
   
    PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.


    另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.

    由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
   
   
    那么外部事务如何利用嵌套事务的 savepoint 特性呢, 我们用代码来说话
   
	ServiceA {
		
		/**
		 * 事务属性配置为 PROPAGATION_REQUIRED
		 */
		void methodA() {
			ServiceB.methodB();
		}
	
	}
	
	ServiceB {
		
		/**
		 * 事务属性配置为 PROPAGATION_REQUIRES_NEW
		 */	
		void methodB() {
		}
		
	}	
   

这种情况下, 因为 ServiceB#methodB 的事务属性为 PROPAGATION_REQUIRES_NEW, 所以两者不会发生任何关系, ServiceA#methodA 和 ServiceB#methodB 不会因为对方的执行情况而影响事务的结果, 因为它们根本就是两个事务, 在 ServiceB#methodB 执行时 ServiceA#methodA 的事务已经挂起了 (关于事务挂起的内容已经超出了本文的讨论范围, 有时间我会再写一些挂起的文章) .

那么 PROPAGATION_NESTED 又是怎么回事呢? 继续看代码


	ServiceA {
		
		/**
		 * 事务属性配置为 PROPAGATION_REQUIRED
		 */
		void methodA() {
			ServiceB.methodB();
		}
	
	}
	
	ServiceB {
		
		/**
		 * 事务属性配置为 PROPAGATION_NESTED
		 */	
		void methodB() {
		}
		
	}	



现在的情况就变得比较复杂了, ServiceB#methodB 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? 从 Juergen Hoeller 的原话中我们可以找到答案, ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint(注意, 这是本文中第一次提到它, 潜套事务中最核心的概念), 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:

1. 改写 ServiceA 如下

	ServiceA {
		
		/**
		 * 事务属性配置为 PROPAGATION_REQUIRED
		 */
		void methodA() {
			try {
				ServiceB.methodB();
			} catch (SomeException) {
				// 执行其他业务, 如 ServiceC.methodC();
			}
		}
	
	}
	


这种方式也是潜套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点. (题外话 : 看到这种代码, 似乎似曾相识, 想起了 prototype.js 中的 Try 函数 )

2. 代码不做任何修改, 那么如果内部事务(即 ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此),
   外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback (+MyCheckedException).
  
  
上面大致讲述了潜套事务的使用场景, 下面我们来看如何在 spring 中使用 PROPAGATION_NESTED, 首先来看 AbstractPlatformTransactionManager


	/**
	 * Create a TransactionStatus for an existing transaction.
	 */
	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

    ... 省略

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}
			if (useSavepointForNestedTransaction()) {
				// Create savepoint within existing Spring-managed transaction,
				// through the SavepointManager API implemented by TransactionStatus.
				// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
				DefaultTransactionStatus status =
						newTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				doBegin(transaction, definition);
				boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
				return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
			}
		}
	}


  
一目了然

1. 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!!

再看 AbstractTransactionStatus#createAndHoldSavepoint() 方法

	/**
	 * Create a savepoint and hold it for the transaction.
	 * @throws org.springframework.transaction.NestedTransactionNotSupportedException
	 * if the underlying transaction does not support savepoints
	 */
	public void createAndHoldSavepoint() throws TransactionException {
		setSavepoint(getSavepointManager().createSavepoint());
	}


  可以看到 Savepoint 是 SavepointManager.createSavepoint 实现的, 再看 SavepointManager 的层次结构, 发现
  其 Template 实现是 JdbcTransactionObjectSupport, 常用的 DatasourceTransactionManager, HibernateTransactionManager
  中的 TransactonObject 都是它的子类 :


  
  JdbcTransactionObjectSupport 告诉我们必须要满足两个条件才能 createSavepoint :
 
2. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+
3. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0


确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了. (全文完)

  • 大小: 33.9 KB
分享到:
评论
36 楼 realreal2000 2006-12-20  
非常好的分析,期待更多文章
35 楼 ahuaxuan 2006-12-14  
决定是精华的好贴,顶起来
34 楼 roc8633284 2006-12-14  
使用嵌套事务是有前提的,就是该嵌套事务可能需要做分支处理。否则用
PROPAGATION_REQUIRED 就足够了,如果子事务有异常,直接回滚。
33 楼 Feiing 2006-11-29  
lithium 写道
J2EE规范不要求应用服务器支持嵌套事务,也就是说,要使用嵌套事务,就不能用JtaTransactionManager,就不能支持分布式事务,对吗?


是的, PROPAGATION_NESTED 在 EJB 中不要求实现, 能不能使用要看 JTA 的具体实现
引用

Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.

Note: Actual creation of a nested transaction will only work on specific transaction managers. Out of the box, this only applies to the JDBC DataSourceTransactionManager when working on a JDBC 3.0 driver. Some JTA providers might support nested transactions as well.
32 楼 lithium 2006-11-29  
J2EE规范不要求应用服务器支持嵌套事务,也就是说,要使用嵌套事务,就不能用JtaTransactionManager,就不能支持分布式事务,对吗?
31 楼 jianfeng008cn 2006-11-29  
Feiing 写道
jianfeng008cn 写道


看了这篇文章后很多人说概念上清楚了,我怎么就觉得很迷糊呢!?仔细琢磨了一下,说一下我的想法和疑惑。
我觉得上面的这种想法其实是合理的,楼主把针对持久层的事务和程序的事务是不是较在一起了呢?(当然我也怀疑是自己犯本质上的错误了)
抛开数据库来理解,如果serviceA中的methodA中有调用ServiceB methodB,如果ServiceB的methodB调用出错需要rollback,那么理所当然,该方法所做的事情都应该取消,回到调用前,即rollback本来就该是这个样子的,哪来的脏数据呢?数据库的rollback是不会有数据库脏数据生成的吧
PROPAGATION_REQUIRES_NEW 的配置当然会有脏数据问题,因为正如他的英文意思,本身就是新的事务的意思呀。
这样说来Service 调用dao的说法也有其合理性,把业务逻辑和持久层很好的分离出来从而更好的剥离业务上的事务和持久层的事务。
我现在的理解是 事务只是保证一系列操作的原子属性,按照楼主的意思我想spring是不是不能处理多数据源情况下的事务处理呢。

经验很少,还望各位不啻指教,感谢了。



呵呵, 事务就是事务, 没有什么 "业务上的事务和持久层的事务" 的说法, 建议你先看一下 http://www.iteye.com/topic/11190


非常感谢,收获不小,继续努力!
30 楼 Feiing 2006-11-29  
jianfeng008cn 写道


看了这篇文章后很多人说概念上清楚了,我怎么就觉得很迷糊呢!?仔细琢磨了一下,说一下我的想法和疑惑。
我觉得上面的这种想法其实是合理的,楼主把针对持久层的事务和程序的事务是不是较在一起了呢?(当然我也怀疑是自己犯本质上的错误了)
抛开数据库来理解,如果serviceA中的methodA中有调用ServiceB methodB,如果ServiceB的methodB调用出错需要rollback,那么理所当然,该方法所做的事情都应该取消,回到调用前,即rollback本来就该是这个样子的,哪来的脏数据呢?数据库的rollback是不会有数据库脏数据生成的吧
PROPAGATION_REQUIRES_NEW 的配置当然会有脏数据问题,因为正如他的英文意思,本身就是新的事务的意思呀。
这样说来Service 调用dao的说法也有其合理性,把业务逻辑和持久层很好的分离出来从而更好的剥离业务上的事务和持久层的事务。
我现在的理解是 事务只是保证一系列操作的原子属性,按照楼主的意思我想spring是不是不能处理多数据源情况下的事务处理呢。

经验很少,还望各位不啻指教,感谢了。



呵呵, 事务就是事务, 没有什么 "业务上的事务和持久层的事务" 的说法, 建议你先看一下 http://www.iteye.com/topic/11190
29 楼 jianfeng008cn 2006-11-29  
引用

在我所见过的误解中, 最常见的是下面这种:


引用

假如有两个业务接口 ServiceA 和 ServiceB, 其中 ServiceA 中有一个方法实现如下

/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
// 调用 ServiceB 的方法
ServiceB.methodB();
}

那么如果 ServiceB 的 methodB 如果配置了事务, 就必须配置为 PROPAGATION_NESTED



这种想法可能害了不少人, 认为 Service 之间应该避免互相调用, 其实根本不用担心这点,PROPAGATION_REQUIRED 已经说得很明白,
如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务,就新建一个事务, 所以 ServiceB#methodB() 的事务只要遵循最普通的规则配置为 PROPAGATION_REQUIRED 即可, 如果 ServiceB#methodB (我们称之为内部事务, 为下文打下基础) 抛了异常, 那么 ServiceA#methodA(我们称之为外部事务) 如果没有特殊配置此异常时事务提交 (即 +MyCheckedException的用法), 那么整个事务是一定要 rollback 的, 什么 Service 只能调 Dao 之类的言论纯属无稽之谈, spring 只负责配置了事务属性方法的拦截, 它怎么知道你这个方法是在 Service 还是 Dao 里 ?


看了这篇文章后很多人说概念上清楚了,我怎么就觉得很迷糊呢!?仔细琢磨了一下,说一下我的想法和疑惑。
我觉得上面的这种想法其实是合理的,楼主把针对持久层的事务和程序的事务是不是较在一起了呢?(当然我也怀疑是自己犯本质上的错误了)
抛开数据库来理解,如果serviceA中的methodA中有调用ServiceB methodB,如果ServiceB的methodB调用出错需要rollback,那么理所当然,该方法所做的事情都应该取消,回到调用前,即rollback本来就该是这个样子的,哪来的脏数据呢?数据库的rollback是不会有数据库脏数据生成的吧
PROPAGATION_REQUIRES_NEW 的配置当然会有脏数据问题,因为正如他的英文意思,本身就是新的事务的意思呀。
这样说来Service 调用dao的说法也有其合理性,把业务逻辑和持久层很好的分离出来从而更好的剥离业务上的事务和持久层的事务。
我现在的理解是 事务只是保证一系列操作的原子属性,按照楼主的意思我想spring是不是不能处理多数据源情况下的事务处理呢。

经验很少,还望各位不啻指教,感谢了。








28 楼 naci007 2006-11-29  
好文呀
27 楼 fishermen 2006-11-28  
看了两遍,真是有收获,虽然暂时还没遇到需要嵌套事务的地方
26 楼 finalbone 2006-11-28  
大家请注意 Juergen Hoeller 的原文

引用

PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.

Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction.

For example, consider parsing a very large input file consisting of account transfer blocks: The entire file should essentially be parsed within one transaction, with one single commit at the end. But if a block fails, its transfers need to be rolled back, writing a failure marker somewhere. You could either start over the entire transaction every time a block fails, remembering which blocks to skip - or you mark each block as a nested transaction, only rolling back that specific set of operations, keeping the previous work of the outer transaction. The latter is of course much more efficient, in particular when a block at the end of the file fails.

Rolling back the entire transaction is the choice of the demarcation code/config that started the outer transaction.

So if an inner transaction throws an exception and is supposed to be rolled back (according to the rollback rules), the transaction will get rolled back to the savepoint taken at the start of the inner transaction. The immediate calling code can then decide to catch the exception and proceed down some other path within the outer transaction.

If the code that called the inner transaction lets the exception propagate up the call chain, the exception will eventually reach the demarcation code of the outer transaction. At that point, the rollback rules of the outer transaction decide whether to trigger a rollback. That would be a rollback of the entire outer transaction then.

So essentially, it depends on your exception handling. If you catch the exception thrown by the inner transaction, you can proceed down some other path within the outer transaction. If you let the exception propagate up the call chain, it's eventually gonna cause a rollback of the entire outer transaction.



PROPAGATION_NESTED 默认情况下只是回滚到子事务开始的地方(savepoint) 父事务不回滚

如果想使用PROPAGATION_NESTED 又想回滚父事务 该怎么办呢?

ServiceA {   
       
    /**  
     * 事务属性配置为 PROPAGATION_NESTED  
     */  
    void methodA() {   
        // do A ...

        ServiceB.methodB(); 
  
        // do A ...
    }   
  
}


OR

ServiceA {   
       
    /**  
     * 事务属性配置为 PROPAGATION_NESTED  
     */  
    void methodA() {   
        // do A ...
        try {   
            ServiceB.methodB();   
        } catch (Exception ex) {   
            throw ex;
        }   
        // do A ...
    }   
  
}



比如有两套系统 一套使用ibatis 一套使用hibernate

当两套系统进行集成整合的时候就会遇到事务嵌套的问题

比如想在 DataSourceTransactionManager 中调用hibernate操作 这时候麻烦就来了

有一种做法是将两套系统都交由 HibernateTransactionManager

因为 HibernateTransactionManager 是可以管理jdbc操作的

不知道将两套系统都交由 DataSourceTransactionManager 会怎么样?

或者两个事务管理器并存 用PROPAGATION_NESTED? 回头试一试...
25 楼 Tin 2006-11-28  
savepoint支持是JDBC 3.0规定必须支持的特性么?不知道我们常用的数据库哪个版本配合哪个驱动支持?
还有,看AbstractPlatformTransactionManager代码,嵌套事务还可以通过JTA的嵌套事务支持,这种用法哪个应用程序服务器支持呢?
看完这篇文章概念上感觉明白了,就是不知道背后支持怎么样:D
手里项目还没有遇到过需要嵌套事务的情况,有机会尝试一下。
24 楼 HH 2006-11-28  
大家都不明白嵌套事务,可见这个东西很少用。

做到现在还没有碰到过需要使用嵌套事务的地方。
23 楼 finalbone 2006-11-28  
个人理解只有需要根据子事务的执行情况进行分支处理的情况下才是nested的用武之地
savepoint是嵌套事务回滚的实现方式 需要注意的是使用它的限制条件

而required_new就更少用到了 一般情况下可以将此部分代码放在事务之外执行 实在剥离不开才会用到
22 楼 Feiing 2006-11-27  
together 写道
Feiing 写道
当然, 就算所有嵌套事务都已经成功, 外部事务还是可能因为嵌套事务的执行结果而导致失败,  此时整个事务都要 roll back ,这也是嵌套事务的重要特性之一, 即外部事务和嵌套事务互相影响

反过来说,所有嵌套事务都执行成功,外部事务也执行成功。那么发部事务要发送commit请求给各个嵌套事务,以同时提交,是这个意思吗?


按照定义是这样的

together 写道

那么对于数据库来说,它相当于在瞬间处理多个事务的commit,在中间的任何一步也是有可能出错的。那这个时候整个事务的回滚如何进行呢?


因为嵌套事务都有自己的 savepoint, 所以整个事务都可以回滚, 至于 savepoint 的具体实现, 那就是数据库厂商的事了.

但是嵌套事务可能会引起效率问题, 如果没有特殊的需求, PROPAGATION_REQUIRED 已经足够了
21 楼 zhh1981 2006-11-27  
分析的很好,现在市面上的书对此都不是讲的很透彻!
20 楼 andyao 2006-11-27  
很好的分析。
终于弄清楚nested和required_new的区别了
19 楼 davidzhao 2006-11-27  
嗯 写的很棒 原来这方面的东西我只是在Oracle的资料上看到的
在使用spring的时候没有注意到
没想到楼主解释的这么详尽
18 楼 together 2006-11-27  
Feiing 写道
当然, 就算所有嵌套事务都已经成功, 外部事务还是可能因为嵌套事务的执行结果而导致失败,  此时整个事务都要 roll back ,这也是嵌套事务的重要特性之一, 即外部事务和嵌套事务互相影响

反过来说,所有嵌套事务都执行成功,外部事务也执行成功。那么发部事务要发送commit请求给各个嵌套事务,以同时提交,是这个意思吗?
那么对于数据库来说,它相当于在瞬间处理多个事务的commit,在中间的任何一步也是有可能出错的。那这个时候整个事务的回滚如何进行呢?
17 楼 boogie 2006-11-26  
绝对OK的文章!

相关推荐

    JAVA开发规范

    - **Spring事务传播机制解惑**:深入理解Spring框架下的事务管理机制,确保事务的正确配置和应用。 ### 表义命名规范 - **规则**:定义了领域对象、服务层、Web层等命名规则,以及常用的中英文术语对照,确保命名...

    松下AFPX-C38AT PLC控制双切刀三边封制袋机系统的伺服电机与温控程序解析

    内容概要:本文详细介绍了基于松下AFPX-C38AT PLC平台的双切刀三边封制袋机控制系统。该系统通过PLC控制四台伺服电机进行切刀和移刀动作以及二轴送袋定位,同时管理两台变频器实现主机和放料电机的同步调速,并利用WK8H模块进行16路温控输出。文中展示了具体的PLC编程实例,如伺服电机的DRVI指令、变频器的同步控制、温控模块的PID调节等。此外,还讨论了硬件配置、触摸屏界面设计、通信协议设置等方面的内容,强调了系统的灵活性和稳定性。 适合人群:从事工业自动化控制领域的工程师和技术人员,尤其是对PLC编程和伺服电机控制感兴趣的读者。 使用场景及目标:适用于需要深入了解PLC控制系统的开发人员,帮助他们掌握伺服电机控制、变频器同步调速和温控模块编程的具体方法,提高实际项目中的应用能力。 其他说明:文章不仅提供了详细的编程示例,还分享了许多实际调试的经验和技巧,有助于读者更好地理解和应用相关技术。

    计算机审计软件的特点与应用.pdf

    计算机审计软件的特点与应用.pdf

    离散傅里叶变换(DFT)分析-Discrete Fourier Transform (DFT) Analysis-matlab

    离散傅里叶变换(DFT)分析 函数[F,FT,Phase]=DFT(T,Signal,Fi,FF,Res,P,Cursor)计算离散傅里叶变换(DFT) 功能概述:离散傅立叶变换(DFT)分析 函数[F,FT,Phase]=DFT(T,Signal,Fi,FF,Res,P,Cursor)是频率域信号分析的通用工具。它在指定的频率范围内计算信号的离散傅立叶变换(DFT),提供可定制的可视化选项。 输入 T(采样时间向量,秒):表示与正在分析的信号样本相对应的时间点。 信号:您希望在频域中检查的数据集或信号。 FI(以赫兹为单位的初始频率):频率分析的起点。 FF(最终频率(Hz):频率分析范围的上限。 Res(分辨率以赫兹为单位):确定傅立叶变换的精度。较小的值会增加分辨率。 P(打印选项): 0:没有生成图。 1: 仅显示震级图。 2: 显示大小和相位图。 光标(在绘图上启用光标)(可选): 1: 当P不

    Matlab实现电转气协同与碳捕集的虚拟电厂优化调度系统

    内容概要:本文详细介绍了如何在Matlab中构建一个综合了垃圾焚烧、碳捕集和电转气(P2G)技术的虚拟电厂优化调度系统。该系统旨在通过合理的设备参数设置、多能流耦合约束以及分段碳价机制的目标函数设计,实现环保与经济效益的最大化。文中展示了具体的数学模型建立方法,如设备参数初始化、能量平衡约束、碳捕集与P2G物料平衡、分时碳成本计算等,并讨论了求解技巧,包括变量定义、求解器选择和约束条件处理等方面的内容。此外,还探讨了垃圾焚烧发电占比变化对P2G设备启停策略的影响,以及不同时间段内的最优调度策略。 适合人群:从事能源系统优化研究的专业人士,特别是那些熟悉Matlab编程并希望深入了解虚拟电厂调度机制的人群。 使用场景及目标:适用于希望提高虚拟电厂运行效率的研究机构或企业。通过本项目的实施,能够更好地理解如何整合多种能源技术,在满足电力供应需求的同时减少碳排放,降低成本。具体应用场景包括但不限于:制定更加科学合理的发电计划;评估新技术引入后的潜在效益;探索不同政策环境下的最佳运营模式。 其他说明:文中提到的一些关键技术点,如碳捕集与P2G的协同工作、垃圾焚烧发电的灵活应用等,对于推动清洁能源的发展具有重要意义。同时,作者也在实践中遇到了一些挑战,如约束条件之间的冲突等问题,并分享了解决这些问题的经验。

    栈的入栈和出栈.pdf

    入栈和出栈的基本操作

    V型永磁同步电机永磁体参数调整与优化技术解析及Maxwell仿真应用

    内容概要:本文详细探讨了V型永磁同步电机中永磁体参数调整的方法和技术,特别是在Maxwell软件中的应用。首先介绍了V型永磁体的关键参数(如V型夹角、磁钢厚度、极弧系数等)及其对电机性能的影响。接着讨论了利用Maxwell进行参数化建模、参数扫描、优化方法(如响应面法、多目标遗传算法)的具体步骤和注意事项。文中还提供了多个实用脚本,涵盖从几何建模、材料属性设置到求解器配置、后处理分析等多个方面。此外,强调了优化过程中应注意的问题,如退磁校验、磁密饱和、涡流损耗等,并给出了一些实战技巧。 适合人群:从事电机设计与仿真的工程师、研究人员,尤其是熟悉Maxwell软件的用户。 使用场景及目标:帮助用户掌握V型永磁同步电机永磁体参数调整的技术要点,提高电机性能指标(如降低齿槽转矩、减少谐波失真、优化转矩波动等)。通过实例和脚本指导,使用户能够在Maxwell中高效地完成仿真和优化任务。 其他说明:文章不仅提供了详细的理论解释,还包括大量实践经验分享和常见问题解决方案,有助于读者更好地理解和应用相关技术。

    光伏发电系统仿真:基于扰动观察法的最大功率点跟踪与储能控制策略

    内容概要:本文详细介绍了光伏发电系统的仿真建模及其控制策略。主要内容分为四个部分:首先是光伏发电系统仿真模型的搭建,通过数学公式和Python代码实现了太阳电池特性的模拟;其次,探讨了扰动观察法(PO)作为最大功率点跟踪(MPPT)的方法,展示了其实现逻辑和代码示例;第三部分讨论了带储能控制策略的设计,利用状态机管理储能系统的充放电过程,确保电力供应平稳;最后进行了负载突变验证实验,评估了系统在极端条件下的稳定性和可靠性。通过这些步骤,作者不仅解释了理论背景,还提供了具体的实现细节和技术挑战。 适合人群:对光伏发电系统感兴趣的研究人员、工程师以及相关领域的学生。 使用场景及目标:适用于希望深入了解光伏发电系统工作原理的人群,尤其是关注最大功率点跟踪技术和储能控制系统设计的应用开发者。目标是帮助读者掌握光伏系统仿真的关键技术,为实际项目提供理论支持和技术指导。 其他说明:文中提供的代码片段可以直接用于实验环境,便于读者动手实践。此外,针对可能出现的问题如耦合振荡等,给出了相应的解决方案。

    电机设计中8极48槽辐条型转子桥参数化建模与优化(基于Maxwell)

    内容概要:本文详细介绍了8极48槽辐条型电机转子桥的参数化建模方法及其优化过程。通过将桥的厚度、过渡圆弧半径和倒角角度作为变量进行参数化处理,利用Maxwell软件实现了自动化仿真和优化。文中展示了具体的Python和VBScript代码示例,用于动态调整桥部尺寸并监控磁密分布,最终通过参数扫描找到最佳设计参数组合,显著降低了磁密峰值和扭矩波动,提高了电机的整体性能。 适合人群:从事电机设计与仿真的工程师和技术人员,尤其是熟悉Maxwell软件的用户。 使用场景及目标:适用于需要优化电机转子桥结构的设计项目,旨在提高电机性能,降低磁密峰值和扭矩波动,确保机械强度的同时提升电磁性能。 其他说明:文章提供了详细的代码示例和操作步骤,帮助读者快速掌握参数化建模技巧,并强调了网格设置和多参数联动优化的重要性。

    风电调频并网系统中高效仿真的4机2区模型及其PSS模式应用

    内容概要:本文详细介绍了用于风电调频并网系统的4机2区模型,该模型能够在短时间内完成长时间跨度的仿真,极大提高了科研和工程分析的效率。文中具体阐述了模型的结构特点,包括两个区域内的发电机组分布、连接方式以及风电场的虚拟惯量控制机制。此外,文章深入解析了四种PSS(电力系统稳定器)模式的工作原理及其在不同工况下的表现,特别是针对风电接入带来的低频振荡问题进行了讨论。通过实例展示了PSS模式对系统稳定性的显著提升效果,并分享了一些实用的调参技巧。 适合人群:从事电力系统仿真、风电并网研究的专业技术人员及高校相关专业师生。 使用场景及目标:适用于需要进行大规模风电调频并网系统仿真的场合,旨在帮助研究人员更好地理解和解决风电接入对电网稳定性的影响,优化风电并网友好度。 其他说明:文章不仅提供了理论分析,还包括具体的Python和Matlab代码示例,便于读者理解和实践。同时强调了在高风电渗透率条件下选择合适PSS模式的重要性。

    LabVIEW Excel工具包:高效自动化生成带格式测试报告的方法与技巧

    内容概要:本文详细介绍了如何使用LabVIEW的Excel工具包来高效生成带有特定格式的测试报告。首先,准备一个Excel模板文件,设置好表头样式、公司LOGO和合并单元格,并用特殊标记占位。然后,通过LabVIEW代码进行Excel操作,如初始化Excel应用、打开和复制模板文件、写入测试数据、设置条件格式、调整列宽以及保存和关闭文件。文中强调了使用二维数组批量写入数据、条件格式设置超标数据标红、精确控制列宽、避免文件覆盖等问题。此外,还提到了一些常见问题及其解决方案,如Excel进程卡死、数据错位等。最终,通过这些方法可以将原本复杂的报告生成过程大幅简化,提高工作效率。 适合人群:熟悉LabVIEW编程的工程师和技术人员,尤其是从事自动化测试和数据分析工作的人员。 使用场景及目标:适用于需要频繁生成格式一致的测试报告的场景,如汽车电子测试、环境监测等领域。目标是通过LabVIEW的Excel工具包实现自动化、高效的报告生成,节省时间和精力。 阅读建议:读者可以通过本文学习如何利用LabVIEW的Excel工具包快速生成带格式的测试报告,掌握关键技术和最佳实践,从而提升工作效率。同时,在实践中应注意模板的设计和代码的优化,以应对各种复杂的需求变化。

    main (4).ipynb

    main (4).ipynb

    计算机数学基础(下).pdf

    计算机数学基础(下).pdf

    基于MATLAB的多智能体系统一致性算法在电力系统分布式经济调度中的应用

    内容概要:本文详细介绍了如何利用MATLAB实现基于多智能体系统一致性算法的电力系统分布式经济调度策略。首先,通过构建邻接矩阵生成函数,处理电网拓扑结构,确保每个节点能够正确获取邻居信息。接着,定义发电机成本函数和负荷效用函数,将两者统一为二次函数形式,以便更好地兼顾发电侧和用电侧的经济性。然后,重点展示了核心的一致性迭代算法,通过拉普拉斯矩阵实现信息扩散,使发电机和负荷之间的增量成本和效益逐步趋于一致。此外,文中还提供了具体的测试案例,包括10台发电机和19个柔性负荷组成的系统,展示了算法的高效性和鲁棒性。最后,强调了通信拓扑设计对收敛速度的影响,并分享了一些调试经验和潜在的应用前景。 适合人群:电力系统研究人员、自动化控制工程师、MATLAB开发者以及对分布式优化算法感兴趣的学者。 使用场景及目标:适用于电力系统经济调度的研究与开发,旨在提高调度效率、降低成本的同时保障系统的稳定性。通过分布式算法替代传统的集中式调度方式,增强系统的隐私保护能力和计算效率。 其他说明:文中提供的MATLAB代码不仅可用于学术研究,还可以进一步应用于实际工程项目中,特别是在含有大量新能源接入的现代电力系统中,展现出更大的优势。

    计算机数控装置课件.pdf

    计算机数控装置课件.pdf

    机器人路径规划中RRT算法的优化与改进方案

    内容概要:本文详细介绍了RRT(快速扩展随机树)路径规划算法的多个优化方法及其具体实现。首先指出原始RRT存在的缺陷,如路径质量差、计算时间长等问题。然后提出了一系列改进措施,包括目标偏向采样、自适应步长控制、路径平滑处理以及椭圆约束采样等。每个改进都附有具体的Python代码片段,并解释了其实现思路和技术细节。此外,文中还讨论了不同改进方案之间的协同使用效果,强调了实际应用中的注意事项。 适合人群:从事机器人路径规划研究的技术人员,尤其是有一定编程基础并希望深入了解RRT算法优化的人群。 使用场景及目标:适用于各种需要高效路径规划的应用场合,如仓储机器人、无人机避障、机械臂运动规划等。主要目标是提高路径规划的速度和质量,同时减少计算资源消耗。 其他说明:尽管这些改进显著提升了RRT的表现,但在实际部署时仍需考虑传感器噪声和系统延迟等因素的影响。作者分享了许多个人实践经验,为读者提供了宝贵的参考。

    计算机试题实例分析.pdf

    计算机试题实例分析.pdf

    基于PLC的自动门禁系统设计与实现:三菱FX3U系列的应用实例

    内容概要:本文详细介绍了利用三菱FX3U系列PLC构建自动门禁系统的全过程。首先阐述了硬件配置方案,包括选用三菱FX3U-32MT作为主控制器,配备多种传感器如红外对射、地磁以及防夹传感器等,并采用适当的执行机构进行门的开闭控制。接着深入解析了梯形图逻辑的设计,涵盖基本开闭逻辑、安全回路设计、滤波处理等方面的内容。文中特别强调了几个关键技术点,如通过定时器控制门的开启时间和防夹保护措施,解决了红外传感器误触发的问题,并引入了GX Works2模拟器用于程序调试。此外,还讨论了如何通过RS485通信接口实现身份验证模块的联网功能及其故障转移机制。最后,作者分享了一些实用的经验教训,例如避免信号干扰的方法和确保系统稳定性的冗余设计。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程有一定基础的人群。 使用场景及目标:适用于需要构建高效可靠的自动门禁系统的场合,旨在提高门禁系统的安全性、可靠性和智能化水平。 其他说明:文中提到的具体案例和解决方案可以为类似项目的实施提供宝贵的参考价值。同时,作者还提供了许多调试技巧和注意事项,有助于读者更好地理解和应用所学知识。

    基于S7-200 PLC与组态王的全自动洗衣机控制系统设计及应用

    内容概要:本文详细介绍了基于西门子S7-200 PLC和组态王软件构建的全自动洗衣机控制系统。主要内容涵盖IO分配、梯形图程序设计、接线图原理图绘制以及组态画面的设计。通过合理的IO分配,如启动按钮、水位传感器等输入设备和电机、进水阀等输出设备的定义,确保系统的精确控制。梯形图程序实现了洗衣机的基本功能,如启动自锁、进水、水位检测、电机启动和排水等功能。接线图确保了电气连接的安全性和可靠性,而组态画面提供了直观的操作界面,使用户能够轻松监控和操作洗衣机。此外,文中还讨论了一些常见问题及其解决方案,如排水阀卡滞、变频器控制等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC编程和组态软件有一定了解的从业者。 使用场景及目标:适用于需要设计和实施全自动洗衣机控制系统的工业生产和家庭应用场景。目标是提高洗衣机的自动化程度,增强用户体验,确保系统的稳定性和安全性。 其他说明:本文不仅提供了详细的理论讲解,还包括了许多实用的技术细节和调试经验,有助于读者更好地理解和掌握相关技术和方法。

    计算机数制转换教案.pdf

    计算机数制转换教案.pdf

Global site tag (gtag.js) - Google Analytics