Spring Data JPA Методы гибернации, помечающие как транзакционные

#java #hibernate #jpa #spring-data-jpa

#java #гибернация #jpa #spring-data-jpa

Вопрос:

Я использую репозиторий Spring data JPA для своего приложения. В настоящее время я использую базовые операции CRUD, предоставляемые по умолчанию репозиториями spring data jpa, и для сложных запросов соединения я пишу пользовательские запросы JPQL следующим образом:

 public interface ContinentRepository extends JpaRepository<Continent, Long>
{
    @Query(value = "SELECT u FROM Continent u JOIN FETCH ... WHERE u.id = ?1")
    public List<Continent> findContinent(Long id);
}
 

В моем классе обслуживания я автоматически подключаю этот репозиторий и выполняю операции с БД.

 @Service
public class MyService
{
    @Autowired
    public ContinentRepository cr;

    public void read()
    {
        var result1 = cr.findContinent(1);
        var result2 = cr.findContinent(2);
    }


    @Transactional
    public void write()
    {
        var c = new Continent();
        // setters
        c = cr.save(c);
    }
}
 

В настоящее время я просто помечаю write() как org.springframework.transaction.annotation.Transactional .

  1. Должен ли я также пометить read() метод с Transactional(readOnly = true) помощью? Поскольку он выполняет только операции чтения.
  2. Должен ли я также пометить findContinent(Long id) как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
  3. В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)
  4. Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?

Ответ №1:

  1. Должен ли я также пометить метод read() транзакционным (только для чтения = true)? Поскольку он выполняет только операции чтения.

На самом деле это не обязательно, однако это может привести к некоторой оптимизации в отношении потребления кэш-памяти в соответствии с this blog https://vladmihalcea.com/spring-read-only-transaction-hibernate-optimization /

  1. Должен ли я также пометить findContinent (длинный идентификатор) как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions

Тот же ответ, что и в первом случае

  1. В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)

В общем, я добавил уровень метода, потому что у меня больше контроля над параметрами, такими как откат

  1. Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?

Я рекомендую вам иметь на уровне обслуживания, потому что там вы можете обновлять много таблиц (поэтому вы можете использовать много репозиториев), и вы хотите, чтобы все ваше обновление было транзакционным.

Комментарии:

1. То, что @Transactional(readOnly = true) избыточно, не совсем верно. Это зависит от уровня изоляции. Хотя это действительно избыточно для READ COMMITED , поведение будет отличаться для REPEATABLE READ и более высоких уровней изоляции, где блокировки чтения не снимаются немедленно

2. Если я аннотирую класс обслуживания с помощью Transactional и метод внутри этого класса обслуживания с помощью Transactional (но с другими свойствами по сравнению с транзакционной аннотацией уровня класса), то какая аннотация будет применена. Поддерживает ли транзакционная аннотация переопределяющие свойства на уровне метода?

3. Кроме того, когда один метод службы вызывает метод из другой службы, и оба имеют распространение as REQUIRED , но другие свойства отличаются. Например: метод с @Transactional in service A вызывает метод с @Transactional(readOnly=true) in service B, тогда создается ли в этом случае новая транзакция?

4. В этой статье описывается приоритетный порядок, в котором будут применяться аннотации baeldung.com /… Но я не могу найти ничего подобного в spring docs.

5. @JavaLearner Если вы аннотируете службу с @Transactional помощью и внутри вызываете метод репозитория, аннотированный с @Transactional помощью, тогда вам необходимо указать распространение REQUIRED для аннотации транзакции репо, чтобы присоединиться к уже существующей транзакции и не создавать другую. Однако вы должны проверить, поддерживает ли ваша база данных это (так и должно быть). В общем, я этого не делаю, потому что я вызываю репозитории только в службах, а классы репозиториев защищены пакетом, чтобы их нельзя было вводить в классы, расположенные за пределами их пакета.

Ответ №2:

  1. Должен ли я также пометить метод read() транзакционным (только для чтения = true)? Поскольку он выполняет только операции чтения.

ДА. Это хорошая практика, вы сразу узнаете, что этот метод ничего не меняет в базе данных, и, что более важно, вы отключите некоторые непреднамеренные изменения в базе данных с помощью этого метода обслуживания. Если этот метод попытается выполнить какое-либо обновление в базе данных, будет вызвано исключение и будет вызван откат.

  1. Должен ли я также пометить findContinent (длинный идентификатор) как транзакционный (только для чтения = true)? Я читал, что все методы по умолчанию помечены как транзакционные https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions

Зависит от того, как вы его используете. Если вы всегда вызываете это из @Sevice, то нет. Я думаю, что это обычный вариант использования, насколько я знаю.

  1. В интерфейсе репозитория я должен пометить транзакционную аннотацию на уровне метода или на уровне интерфейса. (Кроме того, я подозреваю, что большинство пользовательских методов будут доступны только для чтения)

То же, что и 2.

  1. Хорошо ли иметь @Transactional как на уровне сервиса, так и на уровне хранилища?

То же, что и 2.

Комментарии:

1. Что касается # 1, это зависит от поставщика docs.spring.io/spring-framework/docs/current/javadoc-api/org /…

2. Если вы используете Spring Data и Hibernate, это верно. Я говорю из этого опыта, и это наиболее часто используемый стек. Для меня это должно быть приемлемо, если реализация не интерпретирует только для чтения. Это очень важно, когда вы работаете в больших командах.