How to flush data into db inside active spring transaction?

后端 未结 4 2114
谎友^
谎友^ 2020-12-03 03:46

I want to test hibernate session\'s save() method using spring testing framework. @Test method is :

@Test
@Transactional
public void testSave() {
    User ex         


        
相关标签:
4条回答
  • 2020-12-03 03:54

    You should also take care of the importedpackage : in my case I imported

    import javax.transaction.Transactional;

    instead of

    import org.springframework.transaction.annotation.Transactional;

    0 讨论(0)
  • 2020-12-03 03:56
    1. Have a look here with warning about @Transactional tests (Spring Pitfalls: Transactional tests considered harmful). I've used @org.springframework.test.context.jdbc.Sql to re-populate DB in my service tests and @Transactional for controllers.
    2. ConstraintViolationException for controller update test with invalid data have been thrown only when transaction is committed. So I've found 3 options:
      • 2.1 Annotate test with @Commit or with @Transactional(propagation = Propagation.NEVER). Be aware of DB change.
      • 2.2 Use TestTransaction

    Code:

         TestTransaction.flagForCommit();
         TestTransaction.end();
    
    • 2.3 Use TransactionTemplate

    Code:

        @Autowired
        private PlatformTransactionManager platformTransactionManager;
    
        @Test(expected = Exception.class)
        public void testUpdate() throws Exception {
            TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
            transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            String json = ...
            transactionTemplate.execute(ts -> {
                try {
                    mockMvc.perform(put(REST_URL + USER_ID)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json))
                        .andExpect(status().isOk());
                    ...
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            });
    
    0 讨论(0)
  • 2020-12-03 04:03

    If flush is not working then it very much depend on your database isolation level.

    Isolation is one of the ACID properties of database, that defines how/when the changes made by one operation become visible to other concurrent operations.

    I believe your isolation level is set to Read Committed or Repeatable Read.

    0 讨论(0)
  • 2020-12-03 04:09

    Finally I stuck to the following solution:

    First, my @Test methods are not running within spring @Transactional support. See this article to know how dangerous it may be. Next, instead of using @Repository beans inside @Test methods I autowire @Service beans which use @Transactional annotation. The miracle is that @Test method like this

    @Test
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void testSave() {
        Answer created = createAnswer();
        Long generatedId = answerService.save(created);
    //at this moment answer is already in db
        Answer actual=getAnswerById(generatedId);
    ... }
    

    puts my Answer object into database (just after answerService.save(created);) and method getAnswerById goes to DB and extracts it to check if save was correct.
    To eliminate changes made to database in @Test method I recreate database by JdbcTestUtils.executeSqlScript

    0 讨论(0)
提交回复
热议问题