假设我通过使用JPA批注来使用@transactions

因此,要使任何方法在事务下运行,我要添加@transaction批注,而BINGO我的方法应在事务下运行。

为了达到上述目的,我们需要为该类提供一个interface,并且该实例由某个容器进行管理。
同样,我应该始终从接口(interface)引用中调用该方法,以便代理对象可以启动事务。
因此,我的代码将如下所示:

class Bar {
   @Inject
   private FooI foo;
   ...
   void doWork() {
      foo.methodThatRunUnderTx();
   }
}
class FooImpl implements FooI {
   @Override
   @Transaction
   public void methodThatRunUnderTx() {
       // code run with jpa context and transaction open
   }
}
interface FooI {
    void methodThatRunUnderTx();
}

很好,很好

现在让我们说methodThatRunUnderTx做两个逻辑运算

[1]调用某些服务(较长的请求/响应周期,比如说5秒钟),然后获取结果

[2]执行一些jpa实体修改

现在,由于此方法调用很长,并且我们不想长时间保持事务打开,因此我们更改代码,使[2]发生在单独的tx中,而methodThatRunUnderTx不在事务中运行

因此,我们将从@Transaction中删除methodThatRunUnderTx,并在类中添加另一个带有@transaction的方法,假设新方法是methodThatRunUnderTx2,现在要从methodThatRunUnderTx调用此方法,我们必须将其注入(inject)自身并添加一个接口(interface)方法,这样调用才能通过代理对象。

因此,现在我们的代码将如下所示:
class Bar {
   @Inject
   private FooI foo;
   ...
   void doWork() {
      foo.methodThatRunUnderTx();
   }
}
class FooImpl implements FooI {
   @Inject
   private FooI self;
   @Override
   //@Transaction -- remove transaction from here
   public void methodThatRunUnderTx() {
      ...
     self.methodThatRunUnderTx2();// call through proxy object
   }
   @Override
   @Transaction //add transaction from here
   public void methodThatRunUnderTx2() {
       // code run with jpa context and transaction open
   }
}
interface FooI {
    void methodThatRunUnderTx();
    void methodThatRunUnderTx2();
}

现在是问题

我们已经通过methodThatRunUnderTx2()interface设置为公共(public)

但这不是我们想作为FooI的api公开的内容,而不是要从外部调用的。

有什么解决的建议吗?

最佳答案

这就是为什么现代容器不需要实现任何接口(interface)的原因-然后通过动态子类创建代理,或者使用字节码检测。

因此,解决您的设计问题的方法很简单:实现一个包含事务方法的帮助程序类,并将其注入(inject)实现该接口(interface)的类(以及可以从中受益的任何其他类)。

10-06 09:41