JPA cache behaviour when invoke count() method on Spring Data JPA Repository

大城市里の小女人 提交于 2019-12-13 03:55:43

问题


I'm writing a transactional junit-based IT test for Spring Data JPA repository. To check number of rows in table I use side JDBCTemplate.

I notice, that in transactional context invoking of org.springframework.data.repository.CrudRepository#save(S) doesn't take effect. SQL insert in not performed, number of rows in table is not increased.

But If I invoke org.springframework.data.repository.CrudRepository#count after the save(S) then SQL insert is performed and number of rows is increased.

I guess this is behavior of JPA cache, but how it works in details?

Code with Spring Boot:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ErrorMessageEntityRepositoryTest {

    @Autowired
    private ErrorMessageEntityRepository errorMessageEntityRepository;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    @Transactional
    public void save() {
        ErrorMessageEntity errorMessageEntity = aDefaultErrorMessageEntity().withUuid(null).build();
        assertTrue(TestTransaction.isActive());
        int sizeBefore= JdbcTestUtils.countRowsInTable(jdbcTemplate, "error_message");
        ErrorMessageEntity saved = errorMessageEntityRepository.save(errorMessageEntity);
        errorMessageEntityRepository.count(); // [!!!!] if comment this line test will fail
        int sizeAfter= JdbcTestUtils.countRowsInTable(jdbcTemplate, "error_message");
        Assert.assertEquals(sizeBefore+1, sizeAfter);
    }

Entity:

@Entity(name = "error_message")
public class ErrorMessageEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID uuid;
    @NotNull
    private String details;

Repository:

public interface ErrorMessageEntityRepository extends CrudRepository<ErrorMessageEntity, UUID>

回答1:


You are correct this is a result of how JPA works. JPA tries to delay SQL statement execution as long as possible.

When saving new instances this means it will only perform an insert if it is required in order to get an id for the entity.

Only when a flush event occurs will all changes that are stored in the persistence context flushed to the database. There are three triggers for that event to happen:

  1. The closing of the persistence context will flush all the changes. In a typical setup, this is tight to a transaction commit.

  2. Explicitly calling flush on the EntityManager which you might do directly or when using Spring Data JPA via saveAndFlush

  3. Before executing a query. Since you typically want to see your changes in a query.

Number 3 is the effect you are seeing.

Note that the details are a little more complicated since you can configure a lot of this stuff. As usual, Vlad Mihalcea has written an excellent post about it.




回答2:


In order to make the test data not pollute the database, when using the unit test of Spring-test, the transaction will be rolled back by default, that is, @Rollback is true by default. If you want to test the data without rolling back, you can set @Rollback(value = false) . If you are using a MySQL database, after setting up automatic rollback, if you find that the transaction is still not rolled back, you can check whether the database engine is Innodb , because other database engines such as MyISAM and Memory do not support transactions.



来源:https://stackoverflow.com/questions/52714683/jpa-cache-behaviour-when-invoke-count-method-on-spring-data-jpa-repository

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!