2014-10-28 123 views
16

我有一个LocalContainerEntityManagerFactoryBean作为EntityManager实例。如何在Spring中的共享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) 

如果我有这样的变化:

public void clear() { 
    em.getTransaction().begin(); 
    em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate(); 
} 

结果:

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) 

我也试过弹簧数据的JPA,但也失败了:

public interface MyRepository extends CrudRepository<MyEntity, Integer> { 
    @Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true) 
    @Modifying 
    public void clear(); 
} 

所以,我怎样才能创建一个事务和运行在共享春天的背景下,截断?

Spring的应用程序使用启动: SpringApplication.run(AppConfig.class, args);有:

@Bean 
public JpaTransactionManager transactionManager() { 
    return new JpaTransactionManager(emf); 
} 
+0

请发布完整的stacktraces包括引起。 – m3th0dman 2014-10-28 11:02:37

+3

请不要使用'@ Autowired'来代替'@ PersistenceContext'。 – 2014-10-28 11:03:31

+0

'@PersistenceContext'没有改变任何东西。 Stacktrace更新如上。 – membersound 2014-10-28 11:06:26

回答

25

您应该使用TransactionTemplate对象命令式管理的事务:

transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
     @Override 
     protected void doInTransactionWithoutResult(TransactionStatus status) { 
      em.createNativeQuery("TRUNCATE TABLE MyTable).executeUpdate(); 
     } 
    }); 

要创建TransactionTemplate的只是用注射PlatformTransactionManager

transactionTemplate = new TransactionTemplate(platformTransactionManager); 

如果你想使用新的交易只是调用

transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 
2

作为一种变通方法我现在创建了一个新EntityManager明确使用EMF,并手动启动事务。

@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(); 
} 

这可能并不理想,但适用于当下。

+1

没有理由为什么'@ Transactional'不应该工作,你的设置肯定有问题。此外,这两种解决方案都是解决方法,而不是实际解决问题。我想知道的一件事是,你使用了正确的'@ Transactional'来自春季,而不是来自JEE7的更新? – 2014-10-29 09:40:23

+1

我使用javax one – membersound 2014-10-29 11:37:17

+0

而且是你的类路径中的API还是仅作为提供的依赖项?你也没有使用接口,所以确保你启用基于类的代理...最后,你可以添加完整的stacktrace到你的文章? – 2014-10-29 11:47:54

3

Spring Data JPA自动在您的事务中运行CRUD方法(无需设置除事务管理器以外的任何其他事务)。如果你想使用的交易为您的查询方法,你可以简单地添加@Transactional这些:

interface MyRepository extends CrudRepository<MyEntity, Integer> { 

    @Transactional 
    @Modifying 
    @Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true) 
    void clear(); 
} 

在一个较广义的,你在这里宣布什么是逻辑上等同于CrudRepository.deleteAll(),只是它(你的宣言)不遵守JPA级联级联。所以我想知道你真的打算做什么。如果您使用Spring Boot,则应该为您处理激活和事务管理器设置。

如果你想在服务级别使用@Transactional,你需要设置通过任<tx:annotation-driven />@EnableTransactionManagement(包括一个JpaTransactionManager激活基于注解的事务管理貌似激活是在你尝试建立交易缺少的部分在服务层上)。

+0

我认为使用@transactional意味着spring会自动处理你的提交和刷新。 – obesechicken13 2015-11-23 20:52:12

+0

我怀疑是否在Spring中没有设置键。基本上,Spring为你管理实体经理(所以不会让你管理自己的交易),但你没有告诉它如何管理交易。 – 2016-04-05 20:54:53

相关问题