Операції з Spring та JPA

1. Огляд

У цьому підручнику буде обговорено правильний спосіб налаштування весняних транзакцій , використання анотації @Transactional та загальні підводні камені.

Для більш глибокого обговорення конфігурації персистентності ядра перегляньте підручник Spring with JPA.

В основному, існує два різних способи налаштування транзакцій - анотації та AOP - кожен із своїх переваг. Ми збираємось обговорити тут найбільш поширені конфігурації анотацій.

2. Налаштування транзакцій

Spring 3.1 вводить в @EnableTransactionManagement анотацію , які ми можемо використовувати в @Configuration класі і включити підтримку транзакцій:

@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }

Однак якщо ми використовуємо проект Spring Boot і маємо залежності spring-data- * або spring-tx від шляху до класу, тоді управління транзакціями буде ввімкнено за замовчуванням .

3. Налаштування транзакцій за допомогою XML

До версії 3.1, або якщо Java не доступна, ось конфігурація XML із використанням анотацій та підтримки простору імен:

4. Анотація @Transactional

З налаштованими транзакціями ми тепер можемо коментувати бін @Transactional на рівні класу або методу:

@Service @Transactional public class FooService { //... }

Анотація також підтримує подальшу конфігурацію :

  • Розмноження Тип угоди
  • Рівень ізоляції транзакції
  • час очікування для операції, завершеної транзакцією
  • прапор тільки для читання - натяк для постачальника зберігання , що угода повинна бути тільки для читання
  • Відкат правила для угоди

Зауважте, що за замовчуванням відкат відбувається лише під час виконання, без вивірених винятків. Перевірений виняток не викликає відкат транзакції. Звичайно, ми можемо налаштувати цю поведінку за допомогою параметрів анотації rollbackFor та noRollbackFor .

5. Потенційні підводні камені

5.1. Транзакції та довіреності

На високому рівні Spring створює проксі-сервери для всіх класів, анотованих @Transactional - або в класі, або в будь-якому з методів. Проксі-сервер дозволяє фреймворку вводити логіку транзакцій до та після запущеного методу - головним чином для запуску та фіксації транзакції.

Важливо пам’ятати, що якщо транзакційний компонент реалізує інтерфейс, за замовчуванням проксі-сервером буде динамічний проксі Java. Це означає, що будуть перехоплені лише виклики зовнішніх методів, які надходять через проксі. Будь-які виклики із самовикликом не запускатимуть жодної транзакції, навіть якщо метод має анотацію @Transactional .

Ще одне застереження щодо використання проксі-серверів полягає в тому, що @Transactional слід коментувати лише загальнодоступні методи . Методи будь-яких інших видимостей просто ігнорують анотацію мовчки, оскільки вони не проксі-проксі.

У цій статті тут детально розглядаються подальші підводні камені.

5.2. Зміна рівня ізоляції

Ми також можемо змінити рівень ізоляції транзакції:

@Transactional(isolation = Isolation.SERIALIZABLE)

Зверніть увагу, що це насправді було представлено навесні 4.1; якщо запустити наведений вище приклад до Spring 4.1, це призведе до:

org.springframework.transaction.InvalidIsolationLevelException : Стандартний JPA не підтримує власні рівні ізоляції - використовуйте спеціальний JpaDialect для реалізації JPA

5.3. Транзакції лише для читання

Доступна тільки для читання прапора зазвичай створює плутанину, особливо при роботі з JPA; з Javadoc:

Це просто служить підказкою для фактичної підсистеми транзакцій; це не обов'язково призведе до помилки спроб доступу до запису. Менеджер транзакцій, який не може інтерпретувати підказку лише для читання, не буде створювати виняток, коли його запитуватимуть транзакцію лише для читання.

Справа в тому, що ми не можемо бути впевнені, що вставка чи оновлення не відбудуться, коли встановлено прапор readOnly . Ця поведінка залежить від постачальника, тоді як JPA є агностичною.

Важливо також розуміти , що доступний тільки для читання прапор має значення тільки в транзакції. Якщо операція відбувається поза контекстом транзакції, прапор просто ігнорується. Простий приклад, який викликав би метод, анотований:

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

з контексту, що не стосується транзакцій - транзакція не буде створена, а прапорець readOnly буде проігноровано.

5.4. Журналювання транзакцій

Корисним методом для розуміння проблем, пов’язаних з транзакціями, є точне налаштування реєстрації в транзакційних пакетах. Відповідним пакетом навесні є “ org.springframework.transaction”, який слід налаштувати з рівнем реєстрації TRACE.

6. Висновок

Ми розглянули базову конфігурацію транзакційної семантики, використовуючи як Java, так і XML, як використовувати @Transactional та найкращі практики транзакційної стратегії.

Як завжди, код, представлений у цій статті, доступний на Github.