Need explanation on the necessity of a prior flushing to avoid false positives whenTesting with Spring ?

后端 未结 4 1093
伪装坚强ぢ
伪装坚强ぢ 2021-01-02 08:43

In the spring documentation regarding testing, it states:

Avoid false positives when testing ORM code

When you test code involving an

4条回答
  •  再見小時候
    2021-01-02 08:59

    Annotating Spring tests with @Transactional is convenient but it's not how your production code will be executed. The @Transactional annotation will start a transaction prior to running your test method and it will roll it back when the test method finishes.

    While commit is preceded by a flush, the roll-back is not, so a manual flush is a safety-mechanism to ensure all Entity changes are translated to SQL statements.

    A more appropriate design would be to draw the transaction boundaries explicitly like this:

    @Test
    public void testRootObjects() {
    
        final Company newCompany = new Company();
        newCompany.setName("TV Company");
    
        final Long companyId = transactionTemplate.execute(new TransactionCallback() {
            @Override
            public Long doInTransaction(TransactionStatus transactionStatus) {
                entityManager.persist(newCompany);
                return newCompany.getId();
            }
        });
        Company detachedCompany = transactionTemplate.execute(new TransactionCallback() {
            @Override
            public Company doInTransaction(TransactionStatus transactionStatus) {
                Company attachedCompany = entityManager.find(Company.class, companyId);
                assertEquals(newCompany, attachedCompany);
                assertEquals(newCompany.hashCode(), attachedCompany.hashCode());
                return attachedCompany;
            }
        });
        assertEquals(newCompany, detachedCompany);
        assertEquals(newCompany.hashCode(), detachedCompany.hashCode());
    }
    

    The TransactionTemplate will commit your code so there's no need for manual flushes.

    If you call @Transactional service methods through their interface, you won't need the transactionTemplate at all, since you are calling a Spring proxy which will call TransactionInterceptor (assuming you instructed Spring to be aware of transaction annotations: ) and therefore transactions will be started/committed on your behalf.

提交回复
热议问题