Поведение кеша JPA при вызове метода count () в репозитории Spring Data JPA - PullRequest
0 голосов
/ 09 октября 2018

Я пишу транзакционный ИТ-тест на основе Junit для репозитория Spring Data JPA.Для проверки количества строк в таблице я использую сторону JDBCTemplate.

Я замечаю, что в транзакционном контексте вызов org.springframework.data.repository.CrudRepository#save(S) не вступает в силу.SQL-вставка не выполнена, количество строк в таблице не увеличено.

Но если я вызову org.springframework.data.repository.CrudRepository#count после save(S), то SQL-вставка будет выполнена и число строк увеличено.

Полагаю, это поведение кеша JPA, но как это работает в деталях?

Код с 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(name = "error_message")
public class ErrorMessageEntity {

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

Репозиторий:

public interface ErrorMessageEntityRepository extends CrudRepository<ErrorMessageEntity, UUID>

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Вы правы, это результат работы JPA.JPA пытается задержать выполнение оператора SQL как можно дольше.

При сохранении новых экземпляров это означает, что он будет выполнять вставку только в том случае, если это требуется для получения идентификатора для объекта.

Только при возникновении события сброса все изменения, хранящиеся в контексте постоянства, будут сброшены в базу данных.Для этого события существует три триггера:

  1. Закрытие контекста постоянства сбрасывает все изменения.В типичной установке это тесно связано с фиксацией транзакции.

  2. Явный вызов flush для EntityManager, который вы можете сделать напрямую или при использовании Spring Data JPA через saveAndFlush

  3. Перед выполнением запроса.Поскольку вы обычно хотите видеть свои изменения в запросе.

Эффект, который вы видите, - это номер 3.

Обратите внимание, что детали немного сложнее, поскольку выможно настроить много этого материала. Как обычно, Влад Михалча написал отличный пост об этом .

0 голосов
/ 09 октября 2018

Чтобы тестовые данные не загрязняли базу данных, при использовании модульного теста Spring-test транзакция будет откатываться по умолчанию, то есть @Rollback имеет значение true по умолчанию.Если вы хотите проверить данные без отката, вы можете установить @Rollback (значение = false).Если вы используете базу данных MySQL, после настройки автоматического отката, если вы обнаружите, что транзакция все еще не откатана, вы можете проверить, является ли ядро ​​базы данных Innodb, потому что другие механизмы базы данных, такие как MyISAM и Memory, не поддерживают транзакции.

...