2014-10-28 125 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

相關問題