0

我使用Spring 4.3.8.RELEASE和Hibernate 5.1。我有一個線程池在我的上下文在Spring 4中,我如何在主線程之外創建@Transactional?

<bean id="myprojectThreadFactory" class="org.springframework.scheduling.concurrent.CustomizableThreadFactory"> 
    <constructor-arg value="myproject-"/> 
</bean> 
<bean id="myprojectTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 
    <property name="threadFactory" ref="myprojectThreadFactory"/> 
    <property name="corePoolSize" value="${myproject.core.thread.pool.size}" /> 
    <property name="maxPoolSize" value="${myproject.max.thread.pool.size}" /> 
</bean> 

成立,但我怎麼創建我的任務一個線程中的事務,這是我的主線程之外?我想這

 // Cue up threads to execute 
     for (final Organization org : allOrgs) 
     { 
      m_threadExecutor.execute(new Thread(new Runnable(){ 
       @Override 
       @Transactional(propagation=Propagation.REQUIRES_NEW) 
       public void run() 
       { 
        System.out.println("started."); 
        processData(org.getId()); 
        System.out.println("finished."); 
       } 
      })); 

但這導致以下異常

Exception in thread "myproject-1" Exception in thread "myproject-2" org.hibernate.SessionException: Session is closed! 
    at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:132) 
    at org.hibernate.internal.SessionImpl.setCacheMode(SessionImpl.java:1511) 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1109) 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1033) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) 
    at com.sun.proxy.$Proxy68.find(Unknown Source) 
    at org.mainco.subco.core.repo.GenericDao.find(GenericDao.java:123) 
    at org.mainco.subco.organization.repo.OrganizationDaoImpl.find(OrganizationDaoImpl.java:61) 
    at org.mainco.subco.organization.service.OrganizationServiceImpl.getDescendantOrganizations(OrganizationServiceImpl.java:283) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) 
    at com.sun.proxy.$Proxy75.getDescendantOrganizations(Unknown Source) 
    at org.mainco.subco.myproject.repo.myprojectClassDaoImpl.findBymyprojectOrg(myprojectClassDaoImpl.java:89) 
    at org.mainco.subco.myproject.service.myprojectClassServiceImpl.find(myprojectClassServiceImpl.java:300) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) 
    at com.sun.proxy.$Proxy91.find(Unknown Source) 
    at org.mainco.subco.myproject.quartz.ImportClassesWorker.preProcessData(ImportClassesWorker.java:56) 
    at org.mainco.subco.myproject.quartz.AbstractImportDataWorker.processData(AbstractImportDataWorker.java:126) 
    at org.mainco.subco.myproject.quartz.AbstractImportDataWorker.access$0(AbstractImportDataWorker.java:123) 
    at org.mainco.subco.myproject.quartz.AbstractImportDataWorker$1.run(AbstractImportDataWorker.java:110) 
    at java.lang.Thread.run(Thread.java:745) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 

回答

0

使用TransactionTemplate作爲邏輯。像這樣的東西

final TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); 
    taskExecutor.execute(new Runnable() { 
     @Override 
     public void run() { 
      transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
       @Override 
       protected void doInTransactionWithoutResult(TransactionStatus status) { 
       System.out.println("started."); 
       processData(org.getId()); 
       System.out.println("finished."); 
       } 
      }); 
     } 
    }); 
+0

謝謝。有沒有辦法將@Service方法標記爲事務性的,同時指定要使用的事務模板?我問,因爲「過程數據」方法需要30多分鐘,所以我不想讓它成爲單一交易。它呼籲服務方法,我希望每個人都是單獨的交易。 – Dave

0

春天不知道你的Runnable實例什麼。因此,在run方法中添加註釋沒有任何意義。相反,你想要做的就是把@Transactional放在processData的方法上。但是請注意,它應該是Spring bean的方法

UPDATE: 只是試圖標記既@Transactional@Async的商業方法,它爲我工作。我使用了spring 4.3.9.RELEASE和hibernate 5.0.12.Final自帶的版本1.5.4.RELEASE的spring-boot。對於我的@Async配置,我只使用了@EnableAsync。這裏我得到了:

@Test 
@Transactional 
public void test() throws InterruptedException { 
    beanA.testMethodA(); 

    //Sleeping, since after test is completed application is down which leaves @Async transaction not completed. 
    Thread.sleep(3000); 

    System.out.println("Thread in test method: " + Thread.currentThread().getName()); 
    System.out.println("Transaction in test method: " + TransactionSynchronizationManager.getCurrentTransactionName()); 
} 

這裏是一個BeanA的方法。這是事務與傳播默認的水平,這使得它一定到由測試啓動的事務:

@Override 
@Transactional 
public void testMethodA() { 
    beanB.testMethodB(); 

    System.out.println("Thread in method A: " + Thread.currentThread().getName()); 
    System.out.println("Transaction in method A: " + TransactionSynchronizationManager.getCurrentTransactionName()); 
} 

而最後一部分 - 這被標記爲@Async@Transactional一個BeanB的方法。它運行在一個單獨的線程,並在單獨的事務:

@Async 
@Transactional 
@Override 
public void testMethodB() { 
    System.out.println("Thread in method B: " + Thread.currentThread().getName()); 
    System.out.println("Transaction in method B: " + TransactionSynchronizationManager.getCurrentTransactionName()); 
} 

後,我運行測試,我得到以下的輸出:

Thread in test method: main 
Transaction in test method: com.example.stackoverflow.TransactionTest.test 

Thread in method A: main 
Transaction in method A: com.example.stackoverflow.TransactionTest.test 

Thread in method B: SimpleAsyncTaskExecutor-1 
Transaction in method B: com.example.stackoverflow.BeanBImpl.testMethodB 

注意最後兩個語句。標記爲@Async@Transactional的方法正在其自己的事務和它自己的線程中運行。

+0

THAT不起作用。 processData已經調用一個自動裝配的@Service類,標記爲Transactional。我在「運行」塊中添加了Transactional,因爲我剛剛描述的方式產生了相同的錯誤。 – Dave

+0

嗯..奇怪...順便說一句,也許是一個更好的方式,使其異步使用@Async來代替?你可行嗎?一些信息:http://www.baeldung.com/spring-async –

+0

在這種情況下,你可以按照這個答案:https://stackoverflow.com/questions/29258436/nested-transactional-methods-with-async –