AOP,Spring和事务范围

想象一个事务性的,multithreading的java应用程序,使用spring,jdbc和aop,m个包中的n个类都参与数据库转换。 现在让我们说需要在一个事务中确定一组任意类的范围。 此外,在调用事务时提交事务的范围内始终有一个类T.

让我举一个清晰的例子:给定包A,B,Z和类A.Foo,B.Bar和ZT调用各个类的以下实例(可能由不同的调用者和其他类之间):A。 Foo,B.Bar,A.Foo,ZT只有在调用ZT后才会提交事务。 如果应用程序因任何原因而关闭,除非ZT参与,否则交易将永远不会被提交。

实例可以相互调用,并且如前所述,没有公共入口点从单个入口点(如服务层)调用所有实例,这将成为spring的事务标记的简单目标。

现在的问题是:可以使用方面来解决这个问题吗? 如果是这样,那么基本方法是什么? 谢谢。

您不需要单个入口点,但您确实需要能够将事务拦截器应用于所有入口点,以便可重入调用可以参与同一事务。 假设您可以这样做,您可以使用ThreadLocal标志和自定义org.springframework.transaction.support.TransactionSynchronization实现来完成此操作。

当提交可以安全进行时,您可以修改ZT以设置ThreadLocal标志。 在从PlatformTransactionManager调用的TransactionSynchronization.beforeCommit()实现中,您可以检查该标志并使用它来确定是否允许提交继续。 如果标志不存在,您可以通过抛出RuntimeException来强制回滚。

需要注意的是,如果您有其他类型的交易(不涉及您所描述的3个协调类),您需要确保它们不会无意中回滚。 为此,您可以通过另一个ThreadLocal标志在A.Foo,B.Bar和ZT中标记此“特殊事务”,然后在上面提到的beforeCommit()方法中的guard子句中检查该标志。 伪代码:

 void beforeCommit() { if in special transaction if commit flag not set throw new RuntimeException("cancel transaction") end if end if end 

而且,显然,这是一个黑客,我不会主张在绿地系统中做:)。

Spring的习惯用法建议使用一个知道工作单元的服务接口和一个处理关系数据库的持久性接口。 服务接口中的方法应该与您的用例密切相关。 服务实现知道完成用例目标所需的所有模型和持久性包和类。

“实例可以相互调用,并且如前所述,没有公共入口点从单个入口点(如服务层)调用所有实例,这将成为spring的事务标记的简单目标。”

这句话告诉我,你的行为方式不能轻易地适应Spring的习语。 很难确切地说出你想要什么,但听起来你正在抛弃Spring推荐的两个最重要的层。 如果看起来很难与谷物相悖,也许这是你的设计需要重新加工。

“……中间有其他类的不同呼叫者……” – 也许您需要在这些呼叫者上单独声明事务。

您可以使用方面(使用Spring AOP或AspectJ)在XML配置中声明事务。 Spring 2.5及更高版本现在为您提供了使用注释的选项,如果您更喜欢使用XML配置。

你的描述对我来说非常混乱。 也许这也是你遇到困难的部分原因。 我会重新思考或澄清。

随着春季交易和aop你可以做到但它会有点“破解”……

您需要将事务的开始放在所有入口点 – 您只能从启动事务时提交,并且您需要在此事务中使用第二个方面来控制是否提交。

现在告诉spring回滚事务的唯一方法是在事务边界上抛出exception。 因此,如果你进入那个将导致提交的区域Z你需要做什么,然后你需要在线程局部(也可能通过一个方面)放置一些东西,这个“内部”方面会找到并因此不会抛出回滚事务的例外。 如果你没有输入Z那么线程本地将不会获得标志,当你回到内部方面时,将抛出exception以回滚事务。 你可能不得不吞下那个例外。