Java 在独立应用程序中使用@Transactional
我正在开发一个独立的应用程序,它公开了一个RESTAPI 我使用了我能找到的最标准的库。基本上,我使用JPA2、Hibernate(和用于依赖注入的Guice)。以下是我的主要依赖项: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> </
<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;
}
}