Java 如何在Spring中在共享EntityManager上手动启动事务?
我有一个Java 如何在Spring中在共享EntityManager上手动启动事务?,java,spring,spring-data-jpa,entitymanager,Java,Spring,Spring Data Jpa,Entitymanager,我有一个LocalContainerEntityManagerFactoryBean作为EntityManager实例 要快速删除完整表的内容,我想运行以下代码: @Service public class DatabaseService { @Autowired private EntityManager em; @Transactional public void clear() { em.createNativeQuery("TRUNCAT
LocalContainerEntityManagerFactoryBean
作为EntityManager
实例
要快速删除完整表的内容,我想运行以下代码:
@Service
public class DatabaseService {
@Autowired
private EntityManager em;
@Transactional
public void clear() {
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
}
}
结果:
ERROR org.springframework.integration.handler.LoggingHandler: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
ERROR org.springframework.integration.handler.LoggingHandler: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:245)
at com.sun.proxy.$Proxy84.getTransaction(Unknown Source)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
如果我进行此更改:
public void clear() {
em.getTransaction().begin();
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
}
结果:
ERROR org.springframework.integration.handler.LoggingHandler: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
ERROR org.springframework.integration.handler.LoggingHandler: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:245)
at com.sun.proxy.$Proxy84.getTransaction(Unknown Source)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
我也尝试了spring data jpa,但也失败了:
public interface MyRepository extends CrudRepository<MyEntity, Integer> {
@Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true)
@Modifying
public void clear();
}
作为一种解决方法,我现在使用
EMF
创建了一个新的EntityManager
显式,并手动启动事务
@Autowired
private EntityManagerFactory emf;
public void clearTable() {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
tx.commit();
em.close();
}
这可能不太理想,但目前仍然有效。您应该使用
TransactionTemplate
对象来强制管理事务:
transactionTemplate.execute(
status -> em.createNativeQuery("TRUNCATE TABLE MyTable).executeUpdate());
要创建TransactionTemplate
,只需使用注入式PlatformTransactionManager
:
transactionTemplate = new TransactionTemplate(platformTransactionManager);
如果您想使用新事务,只需调用
transactionTemplate.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRES_NEW);
SpringDataJPA在事务中为您自动运行CRUD方法(无需设置事务管理器之外的任何东西)。如果要将事务用于查询方法,只需将
@Transactional
添加到以下内容:
interface MyRepository extends CrudRepository<MyEntity, Integer> {
@Transactional
@Modifying
@Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true)
void clear();
}
接口MyRepository扩展了Crudepository{
@交易的
@修改
@查询(value=“TRUNCATE TABLE MyTable”,nativeQuery=true)
无效清除();
}
更一般地说,您在这里声明的内容在逻辑上等同于crudepository.deleteAll()
,只是它(您的声明)不支持JPA级别的级联。所以我想知道你真的打算这么做。如果您使用的是SpringBoot,那么激活和事务管理器的设置应该由您负责
如果要在服务级别上使用
@Transactional
,则需要设置JpaTransactionManager
,并通过
或@EnableTransactionManagement
激活基于注释的事务管理(看起来激活是您尝试在服务层上创建事务时缺少的部分)
正确的实现方法是创建如下所示的Dao
@Repository
public class DatabaseDao {
@PersistenceContext
private EntityManager em;
public void clear() {
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
}
}
然后从带有@Transactional
注释的服务方法调用dao方法
@Service
public class DatabaseService {
@Autowired
private DatabaseDao dao;
@Transactional
public void clear() {
dao.clear();
}
}
另外,在您的
配置中添加@EnableTransactionManagement
,请发布完整的堆栈跟踪,包括由引起的堆栈跟踪。不要使用@Autowired
而是使用@PersistenceContext
。@PersistenceContext
没有更改任何内容。上面更新了堆栈跟踪。您不应该启动事务我们自己,@Transactional
应该启动它……您在更改后真的尝试过吗?我尝试了@Transactional
和em.getTransaction().begin()
显式,两者都会导致上述相同的错误。@Transactional
没有理由不起作用,一定是您的设置有问题。而且这两种解决方案都是权宜之计,而不是实际解决问题。我想知道的是,您是否使用了正确的@Transactional
spring中的解决方案而不是JEE7中较新的API?API是在类路径中还是仅作为提供的依赖项?此外,您没有使用接口,因此请确保启用基于类的代理…最后,您可以将完整的堆栈跟踪添加到帖子中吗?而不是javax.transaction.Transactional
尝试使用Spring@Transactional
。Depen启用或禁用javax.transaction.Transactional
中的可用类。“暂时有效”可能是软件工程中最常用的一句话在我的情况下,我需要在集成测试中启动一个事务。这节省了我几个小时。谢谢!我认为使用@transactional意味着spring将自动处理您的提交和刷新。我怀疑spring中没有设置密钥。基本上,spring正在管理他为您提供了实体管理器(因此不会让您管理自己的事务),但您没有告诉它如何管理事务。