9

我已经开始使用这里描述的 Guice 方法级事务。我有一条消息

@Inject
private EntityManager entityManager;

@Transactional
public UserSession createSession(User user, String browser) {
    UserSession session = new UserSession(user, browser);
    entityManager.persist(session);
}

从简短的描述来看,我认为应该足够了。但我收到一个错误,因为没有开始交易。只有当我自己开始并提交它时它才有效。

该对象是由 Guice 在我的应用程序开始时在初始化程序中创建的。每个请求使用相同的实例。

为什么它不起作用?

4

5 回答 5

7

@Transactional方法注释通过AOP,其中 Guice 通过创建一个代理对象来满足请求,Foo该对象拦截那些带注释的方法调用并(可选)将它们转发到实际对象。确保满足以下条件:

  1. 您已经通过 Guice 使用该方法创建了对象,@Transactional否则 Guice 将没有机会提供代理。

  2. 类和方法都没有被标记final,因为 AOP 不能轻易地覆盖它们。

  3. 您已经安装了JpaPersistModule或其他形式的PersistModule。从该源代码中请注意,此模块实际上是将 绑定MethodInterceptor@Transactional注释的。

如果这不能完全满足您的需求,请记住,您始终可以使用AOP 文档来编写自己的方法拦截器。祝你好运!

于 2013-01-01T07:20:10.983 回答
2

我遇到了与您类似的问题,通过从@javax.transaction.Transactional 切换到@com.google.inject.persist.Transactional 解决了这个问题。显然 Guice-Persist 不支持来自 Java Transaction API 的 @Transactional 注释。

于 2014-03-04T13:28:42.887 回答
2

再次检查一切后,它没有工作。有趣的是,它在两者之间起作用,但只有一百次。

经过一些额外的测试后,我发现我需要在每个请求上重新创建类。在我刚刚在应用程序启动时创建它们之前。现在它似乎工作得很好。

感谢您的提示帮助我进一步调查。

于 2013-01-01T14:15:41.940 回答
0

我在以下情况下遇到了这个问题,所以我想我也会在这里发布我的解决方案:

BusinessLogic需要两个构造函数参数:MyDao,理论上我可以从 guice 获得,以及我无法guice 获得的其他一些对象。
所以我创建了一个BusinessLogicProvider( extends AbstactProvider),但它不与bind(BusinessLogic.class).toProvider(BusinessLogicProvider)) 一起使用。现在我只是绑定BusinessLogicProvider任何 guice-served 类型:bind(BusinessLogicProvider.class);

在我的BusinessLogicProvider课堂上,我现在可以@Inject使用private Provider<MyDao> daoProvider;

稍后,在BusinessLogicProvider'public BusinessLogic get()方法中,我可以BusinessLogic使用所需的两个参数调用 ' 构造函数:daoProvider.get()另一个我无法从 guice 获取的对象。

陷阱:当my的@Injected不是类型(但 simpy 的类型)时,它将不起作用。 即使ed来自 guice,guice需要在每次实例化时创建一个新的。private Provider<MyDao> daoProvider;BusinessLogicProviderProvider<MyDao>MyDao
@InjectMyDao BusinessLogic

于 2013-11-29T09:05:07.067 回答
0

除了其他答案,特别是 Jeff Bowman 和 uldall 的答案:

确保您的 Guice 版本与您的 JDK/JRE 运行时一致

我刚刚遇到了这个问题,因为我使用的是 Java 17 运行时和不支持它的 Guice (5.0.1) 版本;它至少需要 5.1.0

如果您认为您使用的是正确的 Guice 版本,但它仍然会损坏......

您可能需要调试您的 CLASSPATH。如果您使用的是依赖项管理器:

  1. 确保您的 CLASSPATH 不会碰巧插入“寄生虫”过时版本作为传递依赖项。使用 Gradle,该:dependencies任务将有助于调试。
  2. 您的 IDE 可能有一个错误,它的 CLASSPATH 冲突解决方案(应该用新版本覆盖旧版本的传递依赖项)可能无法按预期工作。这在 Eclipse Buildship 中发生在我身上,我必须明确阻止项目引入过时的依赖项:
    implementation("another-dependency:x.y.z") {
        exclude group: 'com.google.inject', module: 'guice'
    }
    

奖励:验证 Guice 的仪器是否正常工作

当 Guice 未能正确检测代码时没有反馈,这有点烦人,除了随后抛出的异常(例如javax.persistence.TransactionRequiredException)。

为了验证它是否实际工作,检查@Transactional方法中的调用堆栈可能很有用,如下所示:

@Transactional
void myTransactionalMethod() {
  StackWalker.getInstance().forEach(System.out::println);
  // rest of method
}

如果 Guice 的检测工作正常,您会com.google.inject.persist.jpa.JpaLocalTxnInterceptor在标准输出的调用堆栈中找到。

您还可以使用 IDE 的调试器;只需在方法的开头放置一个断点@Transactional并检查调用堆栈。

javax.transaction.Transactional根据 uldall 的回答,这允许验证即使在当前版本的 Guice (5.1.0) 中,Guice 仍然不支持注释。

于 2022-02-14T12:58:46.357 回答