首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何手动处理Spring 4事务?

如何手动处理Spring 4事务?
EN

Stack Overflow用户
提问于 2016-05-20 13:28:25
回答 1查看 3.3K关注 0票数 1

如何以编程方式控制单个@Test方法中的事务边界?Spring4.x文档有一些线索,但是我想我遗漏了一些东西,因为测试抛出了错误:

代码语言:javascript
复制
java.lang.IllegalStateException: 
Cannot start a new transaction without ending the existing transaction first.

测试

代码语言:javascript
复制
import com.hibernate.query.performance.config.ApplicationConfig;
import com.hibernate.query.performance.config.CachingConfig;
import com.hibernate.query.performance.persistence.model.LanguageEntity;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.test.context.transaction.TestTransaction;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.PersistenceContext;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ApplicationConfig.class, CachingConfig.class }, loader = AnnotationConfigContextLoader.class)
@PersistenceContext
@Transactional(transactionManager = "hibernateTransactionManager")
@TestExecutionListeners({})
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests {

    private static Logger logger = LoggerFactory.getLogger(EHCacheTest.class);

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        logger.info("setUpBeforeClass()");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        logger.info("tearDownAfterClass()");
    }

    @Autowired
    private SessionFactory sessionFactory;

    @Test
    public void testTransactionCaching(){
        TestTransaction.start();
        Session session = sessionFactory.getCurrentSession();
        System.out.println(session.get(LanguageEntity.class, 1));
        Query query = session.createQuery("from LanguageEntity le where le.languageId < 10").setCacheable(true).setCacheRegion("language");
        @SuppressWarnings("unchecked")
        List<LanguageEntity> customerEntities = query.list();
        System.out.println(customerEntities);
        session.getTransaction().commit();

        TestTransaction.flagForCommit();
        TestTransaction.end();

        // Second Transaction
        TestTransaction.start();

        Session sessionNew =  sessionFactory.getCurrentSession();
        System.out.println(sessionNew.get(LanguageEntity.class, 1));
        Query anotherQuery = sessionNew.createQuery("from LanguageEntity le where le.languageId < 10");
        anotherQuery.setCacheable(true).setCacheRegion("language");
        @SuppressWarnings("unchecked")
        List<LanguageEntity> languagesFromCache = anotherQuery.list();
        System.out.println(languagesFromCache);
        sessionNew.getTransaction().commit();

        TestTransaction.flagForCommit();
        TestTransaction.end();
    }
}

更新

还有一个细节:

所有出现的session.getTransaction().commit(); 必须删除,因为它们中断了事务工作流程。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-20 14:28:03

TL;DR

为了避免这个问题,只需删除测试方法的第一行并使用已经可用的事务:

代码语言:javascript
复制
@Test
public void testTransactionCaching() {
    // Remove this => TestTransaction.start(); 
    // Same as before
}

详细答复

使用@Transactional或扩展AbstractTransactionalJUnit4SpringContextTests对测试类进行注释时

代码语言:javascript
复制
// Other annotations
@Transactional(transactionManager = "hibernateTransactionManager")
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests { ... }

该类中的每个测试方法都将在事务中运行。更准确地说,Spring (通过使用TransactionalTestExecutionListener)将在每个测试方法的开头打开一个事务,并在测试完成后回滚它。

那么,您的testTransactionCaching测试方法:

代码语言:javascript
复制
@Test
public void testTransactionCaching() { ... }

在开始时有一个打开的事务,并且您试图通过以下方法手动打开另一个事务:

代码语言:javascript
复制
TestTransaction.start();

因此出现了错误:

如果不先结束现有事务,则无法启动新事务。

为了避免这个问题,只需删除测试方法的第一行并使用已经可用的事务。其他TestTransaction.*方法调用没有问题,但只需删除第一个调用即可。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37347976

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档