Принудительное исключение при нетранзакционной записи с помощью Spring JPA Hibernate - PullRequest
0 голосов
/ 05 октября 2018

Контекст

У нас есть REST-приложение Spring Boot, использующее JPA поверх Hibernate (Spring Boot 2.0.x, spring-tx 5.0.x, Hibernate 5.2.x).Базовая база данных - Oracle.

Наша архитектура не предоставляет сущности JPA, вместо этого сервисный уровень преобразует сущности в классы модели DTO, которые открыты для уровня контроллера REST.Для создания обновлений мы не используем автоматическую очистку, но всегда выполняем явный вызов методов CRUD класса обслуживания, которые переводятся в saveAndFlush() или deleteById() в хранилище (для создания / обновления или удаления соответственно).

Цель

Что нам нужно:

  1. Операции только для чтения выполняются без транзакций
  2. Операции записи (одиночные или множественные) выполняются внутриодна транзакция
  3. Мы получаем предупреждение, если забываем объявить транзакцию для операции записи.

Частичное решение

Для этого у нас есть:

  • Суперинтерфейс репозитория помечен @Transactional(propagation=SUPPORTS, readOnly=true), который охватывает пункт 1.

  • Классы службы не аннотированы, а методы записи службы помечены с помощью `@Транзакционные (распространение = ТРЕБУЕМЫЕ), которые охватывают пункт 2.

  • Репозитарий saveAndFlush(entity) и deleteById(id) методы (единственные методы записи, которые в настоящее время вызываются из сервисов), отмечены @Transactional(propagation=MANDATORY), которыевызывает исключениеn будет выброшено, если они выполняются вне контекста транзакции.

Итак, что касается пункта 3, у нас все в порядке, если кто-то определяет новый метод обслуживания, который записывает данные, и забывает применить @Transactional на нем: будет сгенерировано исключение.

Но если кто-то использует другой метод репозитория, который записывает данные и забывает аннотировать его на уровне обслуживания, он не получит транзакцию с уровня обслуживания и выполнится в пределахтранзакционность по умолчанию (на уровне класса), то есть: SUPPORTS.В этом случае, если текущая транзакция не выполняется, флаг readOnly будет игнорироваться, и запись будет выполняться без вывода сообщений.

Обратите внимание, что flushMode в Hibernate установлен на MANUAL, когда флаг readOnly установлен на @Transactional,Если бы у нас было REQUIRED распространение, запись была бы тихо проигнорирована (что также было бы неприемлемо), тогда как в нашем контексте распространения SUPPORTS запись выполнялась без вывода сообщений.


Вопрос

Есть ли способ настроить транзакции Spring / JPA / Hibernate таким образом, чтобы наш репозиторий разрешал нетранзакционные операции чтения, но генерировал исключение при записи любых данных, кроме как с помощью одного из методов, которые мы переопределилиобъявить @Transactional(propagation=MANDATORY)?

Как отмечалось выше, readOnly=true не достигает этого, даже если он устанавливает flushMode в Hibernate.

1 Ответ

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

Это попытка, если проверяющий TransactionManager добивается цели: https://info.michael -simons.eu / 2018/09/25 / validate-nested -action-settings-with-spring-and-spring-boot /

import org.springframework.boot.autoconfigure.transaction.PlatformTransactionManagerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;

@Configuration
class TransactionManagerConfiguration {

    @Bean
    public PlatformTransactionManagerCustomizer<AbstractPlatformTransactionManager> transactionManagementConfigurer() {
        return (AbstractPlatformTransactionManager transactionManager) -> transactionManager
            .setValidateExistingTransaction(true);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...