Java 在独立应用程序中使用@Transactional

Java 在独立应用程序中使用@Transactional,java,spring,hibernate,jpa,Java,Spring,Hibernate,Jpa,我正在开发一个独立的应用程序,它公开了一个RESTAPI 我使用了我能找到的最标准的库。基本上,我使用JPA2、Hibernate(和用于依赖注入的Guice)。以下是我的主要依赖项: <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version> </

我正在开发一个独立的应用程序,它公开了一个RESTAPI

我使用了我能找到的最标准的库。基本上,我使用JPA2、Hibernate(和用于依赖注入的Guice)。以下是我的主要依赖项:

<dependency>
  <groupId>com.google.inject</groupId>
  <artifactId>guice</artifactId>
  <version>3.0</version>
</dependency>

<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0.2</version>
</dependency>

<dependency>
  <groupId>org.hibernate.javax.persistence</groupId>
  <artifactId>hibernate-jpa-2.1-api</artifactId>
  <version>1.0.0.Final</version>
</dependency>

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-entitymanager</artifactId>
  <version>4.3.10.Final</version>
</dependency>
我不想每次需要事务时都使用try/catch。在另一个项目中,使用servlet容器中的Spring,我可以这样编写:

@Transactional
public void foo() {
  doSomething();
}
有没有非spring解决方案?(我已经使用Guice进行依赖项注入)

编辑(回答Adam Siemion)。下面是如何通过自定义GUI的EntityManager提供程序来创建1个EntityManager/线程。这对我来说仍然很危险,因为在下一个事务中可以使用同一个EntityManager(可能处于脏状态):

public class EntityManagerProvider implements Provider<EntityManager> {

  private static ThreadLocal<EntityManager> entityManagerThreadLocal
    = new ThreadLocal<>();

  @Inject
  private EntityManagerFactory entityManagerFactory;

  @Override
  public EntityManager get() {
    EntityManager entityManager = entityManagerThreadLocal.get();
    if(entityManager == null) {
      entityManager = entityManagerFactory.createEntityManager();
      entityManagerThreadLocal.set(entityManager);
    }
    return entityManager;
  }

}
公共类EntityManagerProvider实现提供程序{
私有静态ThreadLocal EntityManager ReadLocal
=新的ThreadLocal();
@注入
私人实体管理工厂实体管理工厂;
@凌驾
公共实体管理器get(){
EntityManager EntityManager=entityManagerThreadLocal.get();
if(entityManager==null){
entityManager=entityManagerFactory.createEntityManager();
entityManager readLocal.set(entityManager);
}
返回实体管理器;
}
}

您可以绑定自定义拦截器

TransactionalMethodInterceptor interceptor = new TransactionalMethodInterceptor();
名义上:

bindInterceptor(annotatedWith(Transactional.class), any(), interceptor);
bindInterceptor(any(), annotatedWith(Transactional.class), interceptor);
但是首先将
EntityManager
注入到您的
TransactionalMethodInterceptor

requestInjection(interceptor);
它将截获对使用
事务性
注释注释的方法的所有调用

你的拦截器可能是这样的:

class TransactionalMethodInterceptor implements MethodInterceptor {

  @javax.inject.Inject
  private EntityManager em;

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    try {
      Object result = invocation.proceed();
      em.commit();
    } catch (Exception e) {
      em.rollback();
      throw e;
    }
  }
}


MethodInterceptor
MethodInvocation
来自库。

我想您可以使用AspectJ来实现这些目的。仔细检查一下这个例子


在这种情况下,您应该在aspect中只声明一次try catch块

非spring解决方案是javaEE@RomanC我不明白你的意思。阿法克,爪哇EE!=servlet容器。在JavaEE中,我看到
javax.transaction.Transactional
已经存在,但我似乎缺少一些配置(或实现)来让它工作。这一点很清楚。令人印象深刻的是,如此少的代码行是如此强大:)然而,只有在DAO类和拦截器中获得了相同的EntityManager实例,并且很容易理解,我才能让它工作。到目前为止,我找到的唯一方法是将
EntityManager
作为
Singleton
注入,这看起来像是反模式。你有更好的解决办法吗?是的,你完全正确。我知道两种选择:
DataSourceTransactionManager
来自Spring或编写您的实现。如果您选择了第二个选项,请在此处共享代码,以便我可以从第一个选项进行切换!:)哦,您使用JPA,所以您不使用
DataSource
,而是使用
EntityManager
,所以我想
DataSourceTransactionManager
不是一个选项。
Singleton
让我想到了多线程问题。多线程问题让我想到了
ThreadLocal
(基本上,我将
EntityManager
存储在
Thread
中),这确保了
EntityManager
不会在多个线程之间共享。我已经测试过了,但我不知道它是否仍然是一个反模式。
class TransactionalMethodInterceptor implements MethodInterceptor {

  @javax.inject.Inject
  private EntityManager em;

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    try {
      Object result = invocation.proceed();
      em.commit();
    } catch (Exception e) {
      em.rollback();
      throw e;
    }
  }