在Spring4中,如何在主线程之外创建@Transactional?

在Spring4中,如何在主线程之外创建@Transactional?,spring,multithreading,hibernate,spring-transactions,transactional,Spring,Multithreading,Hibernate,Spring Transactions,Transactional,我正在使用Spring4.3.8.RELEASE和Hibernate5.1。我在上下文中设置了一个线程池 <bean id="myprojectThreadFactory" class="org.springframework.scheduling.concurrent.CustomizableThreadFactory"> <constructor-arg value="myproject-"/> </bean> <bean id="mypro

我正在使用Spring4.3.8.RELEASE和Hibernate5.1。我在上下文中设置了一个线程池

<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>
但这导致了以下例外情况

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)

Spring对您的可运行实例一无所知。因此,在
run
方法上添加注释没有任何意义。相反,您要做的是将
@Transactional
放在
processData
方法上。但是请注意,这应该是一个springbean的方法

更新: 刚刚尝试用
@Transactional
@Async
标记一个业务方法,这对我来说很有效。我使用了Spring4.3.9.RELEASE和Hibernate5.0.12.Final附带的1.5.4.RELEASE版本的SpringBoot。对于我的
@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());
}
这里有一个比纳的方法。它是事务性的,具有默认的传播级别,使其绑定到由测试启动的事务:

@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());
}
最后一部分是BeanB的方法,标记为
@Async
@Transactional
。它在单独的线程和单独的事务中运行:

@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
的方法在其自己的事务和线程中运行。

Spring对可运行实例一无所知。因此,在
run
方法上添加注释没有任何意义。相反,您要做的是将
@Transactional
放在
processData
方法上。但是请注意,这应该是一个springbean的方法

更新: 刚刚尝试用
@Transactional
@Async
标记一个业务方法,这对我来说很有效。我使用了Spring4.3.9.RELEASE和Hibernate5.0.12.Final附带的1.5.4.RELEASE版本的SpringBoot。对于我的
@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());
}
这里有一个比纳的方法。它是事务性的,具有默认的传播级别,使其绑定到由测试启动的事务:

@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());
}
最后一部分是BeanB的方法,标记为
@Async
@Transactional
。它在单独的线程和单独的事务中运行:

@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
的方法在其自己的事务和线程中运行。

用于逻辑。像这样的

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.");
                }
            });
        }
    });  
用于逻辑。像这样的

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.");
                }
            });
        }
    });  

那不行。processData已在调用标记为Transactional的autowired@Service类。我在“run”块周围添加了事务性代码,因为我刚才描述的方法产生了相同的错误。嗯。。奇怪。。。顺便说一句,使用@Async可能是使其异步化的更好方法?对你来说可行吗?一些信息:在这种情况下,你可以遵循以下答案:谢谢,但为什么你觉得它很奇怪@事务总是绑定到主线程,因此新线程需要找到另一种创建事务的方法。从您发布的Async链接中,不会创建新事务,除非我有误解。
@Transactional
并不总是绑定到主线程,正如我更新的示例所示。没错-
@Async
本身不会创建新事务。在本例中,
TransactionSynchronizationManager.getCurrentTransactionName()
显示为null,这意味着该方法在运行时根本没有事务,即使调用bean是事务性的。这不起作用。processData已在调用标记为Transactional的autowired@Service类。我在“run”块周围添加了事务性代码,因为我刚才描述的方法产生了相同的错误。嗯。。奇怪。。。顺便说一句,使用@Async可能是使其异步化的更好方法?对你来说可行吗?一些信息:在这种情况下,你可以遵循以下答案:谢谢,但为什么你觉得它很奇怪@事务总是绑定到主线程,因此新线程需要找到另一种创建事务的方法。从您发布的Async链接中,不会创建新事务,除非我有误解。
@Transactional
并不总是绑定到主线程,正如我更新的示例所示。没错-
@Async
本身不会创建新事务。在本例中,
TransactionSynchronizationManager.getCurrentTransactionName()
显示为null,这意味着即使调用bean是事务性的,该方法也在没有事务的情况下运行。谢谢。在指定要使用的事务模板时,是否有方法将@Service方法标记为事务性的?我问这个问题是因为“processData”方法需要30分钟,所以我不想让它成为一个事务。它调用服务方法,我希望这些方法中的每一个都是单独的事务。谢谢。在指定要使用的事务模板时,是否有方法将@Service方法标记为事务性的?我问这个问题是因为“processData”方法需要30分钟,所以我不想让它成为一个事务。它调用服务方法,我希望这些方法中的每一个都是独立的事务。