假设我通过使用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)的类(以及可以从中受益的任何其他类)。