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

时间:2015-07-02 18:43:22

标签: java spring hibernate jpa

我正在开发一个暴露REST API的独立应用程序。

我用我能找到的最标准的库来制作它。基本上,我使用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>

EntityManagerFactoryEntityManager是通过自定义Guice Provider注入的。

一切正常,但到目前为止,我必须手动处理交易,如:

@javax.inject.Inject
private EntityManager em;

public void foo() {
  try {
    em.getTransaction().begin();
    doSomething();
    em.getTransaction().commit();
  } catch() {
    em.getTransaction().rollback();
  }
}
每次我需要交易时,我都不想使用try / catch。在另一个项目中,将Spring放在servlet容器中,我可以这样编写:

@Transactional
public void foo() {
  doSomething();
}

是否有非弹簧解决方案? (我已经使用Guice进行依赖注入)。

编辑(回答Adam Siemion)。这是我如何通过自定义我的Guice的EntityManager提供程序来创建1个EntityManager / Thread。它对我来说似乎仍然很危险,因为可以在下一个事务中使用相同的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;
  }

}

2 个答案:

答案 0 :(得分:2)

您可以绑定自定义拦截器

TransactionalMethodInterceptor interceptor = new TransactionalMethodInterceptor();
Guice中的

bindInterceptor(annotatedWith(Transactional.class), any(), interceptor);
bindInterceptor(any(), annotatedWith(Transactional.class), interceptor);

但首先将EntityManager注入您的TransactionalMethodInterceptor

requestInjection(interceptor);

将拦截对使用Transactional注释注释的方法的所有调用。

你的拦截器可能是这些方面的东西:

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;
    }
  }

}

MethodInterceptorMethodInvocation来自aopalliance库。

答案 1 :(得分:1)

我认为您可以将AspectJ用于此类目的。 Kidnly检查这个例子

How to swallow a exception at AfterThrowing in AspectJ

在这种情况下,您应该只在方面声明一次try-catch块