Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring@transaction在junit的非调试模式下未按预期工作_Java_Spring_Hibernate_Junit_Transactions - Fatal编程技术网

Java Spring@transaction在junit的非调试模式下未按预期工作

Java Spring@transaction在junit的非调试模式下未按预期工作,java,spring,hibernate,junit,transactions,Java,Spring,Hibernate,Junit,Transactions,所有MyService方法都是事务性的。下面的junit测试获取项目数,保存一个新项目,并获取项目数以确保计数已增加1 public class MyTest extends ServiceTest{ 1. int countBefore = myService.getCount(); //return n 2. myService.add(item); //item is really added to DB 3. i

所有MyService方法都是事务性的。下面的junit测试获取项目数,保存一个新项目,并获取项目数以确保计数已增加1

public class MyTest extends ServiceTest{

    1. int countBefore = myService.getCount();    //return n
    2. myService.add(item);                       //item is really added to DB
    3. int countAfter  = myService.getCount();    //return n (sometimes n+1)
}

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED)
getCount(){…}

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE)
add(){…}


调试时(3.)返回n+1,这正是我想要的。但是在没有调试的情况下运行测试时,我得到n

即使有时在运行测试时,我得到n+1,下次我得到n,并且在比较两次执行之间的std输出时,它看起来完全相同。我已经启用了log4j.logger.org.springframework.transaction=TRACE,可以看到:

Initializing transaction synchronization
Getting transaction for MyService.getCount
...
Completing transaction for MyService.getCount
Clearing transaction synchronization

...

Initializing transaction synchronization
Getting transaction for MyService.add
...
Completing transaction for MyService.add
Clearing transaction synchronization

...

Initializing transaction synchronization
Getting transaction for MyService.getCount
...
Completing transaction for MyService.getCount
Clearing transaction synchronization
所以事务一个接一个地执行,但是(3.)怎么可能看不到保存的项目呢

事务管理在我的测试类中按照以下设置:

我怎样才能发现哪里出了问题?
谢谢

也有类似的问题,但在我的例子中,它没有回滚。您似乎忘记添加@Transactional。来自文档()

交易管理

在TestContext框架中,事务由 默认配置的TransactionalTestExecutionListener, 即使您没有在您的服务器上显式声明@TestExecutionListeners 考试班。但是,要启用事务支持,您必须 在ApplicationContext中配置PlatformTransactionManager bean 通过@ContextConfiguration语义加载(更多详细信息 (见下文)。此外,您必须申报Spring的 @在类或方法级别为您的 测试

下面是上面链接的示例

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional
public class FictitiousTransactionalTest {

@BeforeTransaction
public void verifyInitialDatabaseState() {
    // logic to verify the initial state before a transaction is started
}

@Before
public void setUpTestDataWithinTransaction() {
    // set up test data within the transaction
}

@Test
// overrides the class-level defaultRollback setting
@Rollback(true)
public void modifyDatabaseWithinTransaction() {
    // logic which uses the test data and modifies database state
}

@After
public void tearDownWithinTransaction() {
    // execute "tear down" logic within the transaction
}

@AfterTransaction
public void verifyFinalDatabaseState() {
    // logic to verify the final state after transaction has rolled back
}

}

到目前为止,我找到了一个通过测试的解决方案,就是将assert放在后转换方法中

公共类MyTest扩展了ServiceTest{

@Test
public void test(){
    1. int countBefore = myService.getCount();    //return n
    2. myService.add(item);                       //item is really added to DB
}
@后交易 public void verifyFinalDatabaseState(){ 3.int countAfter=myService.getCount();//返回n(有时为n+1) //现在总是返回n+1 }
由于当前正在运行的事务设置为,因此您有两个选项:

  • 您可以从测试方法中删除
    @Transactional
    ,并依赖您的服务方法
    @Transactional
    边界。当您调用:

    int countBefore = myService.getCount();
    myService.add(item);
    int countAfter  = myService.getCount();
    
  • 每个服务调用都将在一个独立的事务中运行,就像在运行时生产调用中一样

  • 您在添加项目后立即刷新Hibernate会话:

    int countBefore = myService.getCount();
    myService.add(item);
    transactionTemplate.execute(new TransactionCallback<Void>() {
        @Override
        public Company doInTransaction(TransactionStatus transactionStatus) {
            entityManager.flush();
            return null;
        }
    });
    int countAfter  = myService.getCount();
    
    intcountbefore=myService.getCount();
    myService.add(项目);
    execute(新建TransactionCallback(){
    @凌驾
    上市公司交易(交易状态交易状态){
    entityManager.flush();
    返回null;
    }
    });
    int countAfter=myService.getCount();
    

  • HQL/JPQL计数查询应该在自动刷新模式下触发刷新,但是。

    我会在评论中问这个问题,但由于我的声誉不允许,我会尝试提供一个答案

    您可能正在使用和ORM缓存计数查询的结果。根据您的add/getCount方法的实现方式以及ORM和数据源的配置,在第二次调用getCount时,您可能会在第一次调用getCount时获得缓存值


    但是,这并不能解释为什么在调试模式下,您总是得到正确的结果。

    您是否使用了
    ?请看我的答案。您可以添加配置和TestClass吗?@Xstian我添加了conf和test类。thxIt是一种奇怪的行为。。配置似乎工作正常。唯一的想法是
    具有未添加,但已更新。这是可能的?添加方法仅执行
    插入
    更新
    ?项目正在添加,然后在同一发送中更新。这可能是问题吗?我注意到您说过您的方法具有@Transactional,但我仍然必须在我的方法级别上为我的测试添加它们。即使添加@在测试方法上,我得到了相同的行为。您在事务上的传播是什么?@Transactional(propagation=propagation.REQUIRES_NEW,isolation=isolation.SERIALIZABLE我也用这个信息更新了这个问题已经尝试了你的答案的两个选项。1-我的测试不是@transactional,2-我没有entityManager,我使用的是sessionFactory.getCurrentSession.flush()仍然有相同的奇怪行为。到目前为止,唯一有效的方法是@AfterTransaction中的断言。请参阅我的答案。您也可以使用Hibernate会话。按照我的建议尝试使用
    transactionTemplate
    。我正在使用Hibernate,您的想法也浮现在我的脑海中。如何绕过Hibernate缓存?看看这里的表3.5。我相信您可能会对hibernate.cache.use_query_cache和hibernate.cache.use_二级_缓存感兴趣。请尝试在hibernate配置中将这两个设置都设置为false。 @AfterTransaction public void verifyFinalDatabaseState() { 3. int countAfter = myService.getCount(); //return n (sometimes n+1) //Now always return n+1 }
    int countBefore = myService.getCount();
    myService.add(item);
    int countAfter  = myService.getCount();
    
    int countBefore = myService.getCount();
    myService.add(item);
    transactionTemplate.execute(new TransactionCallback<Void>() {
        @Override
        public Company doInTransaction(TransactionStatus transactionStatus) {
            entityManager.flush();
            return null;
        }
    });
    int countAfter  = myService.getCount();