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

标签 java spring hibernate jpa

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

我使用了我能找到的最多的标准库。基本上,我使用 JPA2、Hibernate(和用于依赖注入(inject)的 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 注入(inject)。

一切正常,除了到现在为止,我必须像这样手动处理交易:

@javax.inject.Inject
private EntityManager em;

public void foo() {
  try {
    em.getTransaction().begin();
    doSomething();
    em.getTransaction().commit();
  } catch() {
    em.getTransaction().rollback();
  }
}

而且我不想在每次需要交易时都使用 try/catch。在另一个项目中,在 servlet 容器中使用 Spring,我可以简单地这样写:

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

有没有非spring的解决方案? (我已经使用 Guice 进行依赖注入(inject))。

编辑(对 Adam Siemion 的回答)。以下是我如何通过自定义 Guice 的 EntityManager Provider 创建 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;
  }

}

最佳答案

可以绑定(bind)自定义拦截器

TransactionalMethodInterceptor interceptor = new TransactionalMethodInterceptor();

在 Guice 中:

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

但首先将 EntityManager 注入(inject)您的 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图书馆。

关于java - 在独立应用程序中使用@Transactional,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31192272/

相关文章:

java - Mysql blob 图片转换为 awt.image,然后 awt.image 转换为 blob,无需更改大小

spring - 与 Spring Data JPA 保持一对一关系

spring - dockerized 环境中的 Keycloak 和 Spring Boot Web 应用程序

java - 在生产系统中使用 Hibernate 和 flyway

java - 如何在 Hibernate 中维护/生成表以用于多用户目的?

java - hibernate 过滤器不适用于子选择查询

java - 为什么 ArrayList 上的 contains() 方法总是返回 false?

java - 集合<字符串>

java - 使用 KafkaProperties 配置多个 kafka 主题名称的最佳方法是什么

java - 在spring mvc中执行jdbc调用