问题描述
想象一个使用 spring、jdbc 和 aop 的事务性多线程 java 应用程序,其中 m 个包中的 n 个类都参与数据库事务.现在假设需要在一个事务中限定一组任意的类.此外,在调用时提交事务的范围内总是有一个类 T.
imagine a transactional, multithreaded java application using spring, jdbc and aop with n classes in m packages all taking part in database transations. Now let's say there is the need to scope an arbitrary set of classes within one transaction. Furthermore there is always one class T within the scope that commits the transaction when called.
为了清楚起见,让我举一个例子:给定包 A、B、Z 和类 A.Foo、B.Bar 和 Z.T.各个类的以下实例被调用(可能由不同的调用者和中间的其他类调用):A.Foo,B.Bar,A.Foo,Z.T只有在调用 Z.T 后才会提交事务.如果应用程序因任何原因关闭,除非 Z.T 参与,否则永远不会提交事务.
Let me give an example for clarity:Given the packages A,B,Z and classes A.Foo, B.Bar and Z.T.The following instances of the respective classes are called (possibly by different callers with other classes in between): A.Foo,B.Bar,A.Foo,Z.TThe transactions will be committed only after Z.T is called. Should the application shut down for whatever reason the transaction will never be committed unless Z.T gets involved.
实例可以相互调用,正如已经提到的,没有从单个入口点(如服务层)调用所有实例的公共入口点,这将使 spring 的事务标记成为一个简单的目标.
Instances can call each other and, as already mentioned, there is no common entry point calling all instances from a single point of entry (like a service layer) which would make an easy target for spring's transactional tag.
现在的问题是:这个问题可以用方面来解决吗?如果是这样,基本方法是什么?谢谢.
Now the question: can this problem be solved using aspects ? If so, what could be the basic approach ?Thanks.
推荐答案
您不需要单个入口点,但确实需要能够将事务拦截器应用于所有入口点,以便可重入调用参与同一交易.假设您可以这样做,您可以使用 ThreadLocal 标志和自定义 org.springframework.transaction.support.TransactionSynchronization
实现来完成此操作.
You don't need a single point of entry, but you do need the ability to apply the transactional interceptor to all entry points so that re-entrant calls can participate in the same transaction. Assuming that you can do that, you could accomplish this with a ThreadLocal flag and a custom org.springframework.transaction.support.TransactionSynchronization
implementation.
当提交可以安全进行时,您可以修改 Z.T 以设置 ThreadLocal 标志.在从 PlatformTransactionManager
调用的 TransactionSynchronization.beforeCommit()
实现中,您可以检查标志并使用它来确定是否允许提交继续进行.如果标志不存在,您可以通过抛出 RuntimeException
来强制回滚.
You'd modify Z.T to set the ThreadLocal flag when a commit is safe to proceed. In your TransactionSynchronization.beforeCommit()
implementation, which is invoked from the PlatformTransactionManager
, you can check the flag and use that to determine whether to allow the commit to proceed. You can force a rollback by throwing a RuntimeException
if the flag is not present.
一个警告是,如果您有其他类型的事务(不涉及您描述的 3 个协调类),您需要确保它们不会被无意中回滚.为此,您可以通过另一个 ThreadLocal 标志在 A.Foo、B.Bar 和 ZT 中标记此特殊事务",然后在上述 beforeCommit()
方法的保护子句中检查该标志.伪代码:
One caveat would be if you have other types of transactions (that don't involve the 3 co-ordinating classes you've described), you'll need to ensure that they don't get rolled back inadvertently. To do this, you could flag this "special transaction" in A.Foo, B.Bar and Z.T via another ThreadLocal flag, then check that flag in a guard clause in the beforeCommit()
method mentioned above. Pseudocode:
void beforeCommit() {
if in special transaction
if commit flag not set
throw new RuntimeException("cancel transaction")
end if
end if
end
而且,显然,这是一个黑客行为,我不提倡在绿地系统中进行:)
And, obviously, this is a hack and I wouldn't advocate doing in a greenfield system :).
这篇关于AOP、Spring 和事务范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!