Чому мені потрібна транзакція в режимі глибокого сну для операцій лише для читання?


107

Чому мені потрібна транзакція в режимі глибокого сну для операцій лише для читання?

Чи вкладається наступна транзакція блокування в БД?

Приклад коду для отримання з БД:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Чи можна використовувати session.close() замість tx.commit()?


9
Трансакцію вимагає сама БД. Про режим автоматичного
керування

@BheshGurung я думаю, нам потрібен переклад лише для операції запису
user93796

4
Ви читали частину "Розвінчання міфів про самозакоханість" у посиланні?
Bhesh Gurung

Відповіді:


131

Насправді у вас можуть бути причини маркувати транзакції як лише для читання.

  1. Трансакції для читання можуть виглядати справді дивними, і часто люди не відзначають методів транзакцій у цьому випадку. Але JDBC все одно створить транзакції, просто це буде працювати, autocommit=trueякщо інша опція не була встановлена ​​явно.
  2. Але немає гарантії, що ваш метод не запише в базу даних. Якщо ви позначите метод як @Transactional(readonly=true), Spring встановить транзакцію JDBC в режим лише для читання, таким чином, ви будете диктувати, чи можливо насправді записати в БД в межах цієї транзакції. Якщо ваша архітектура громіздка, і деякі члени команди можуть вирішити поставити запит на модифікацію там, де цього не передбачається, цей прапор вказує на проблемне місце.
  3. Також БД можуть оптимізувати транзакції лише для читання, але це, звичайно, специфічно для БД. Наприклад, MySQL додав підтримку для цього лише в InnoDB, починаючи з версії 5.6.4.
  4. Якщо ви не використовуєте JDBC безпосередньо, а скоріше ORM, це може бути проблематично. Наприклад, спільнота зі сплячого режиму говорить, що робота поза транзакцією може спричинити непередбачувану поведінку. Це відбувається тому, що Hibernate відкриє транзакцію, але не закриє її самостійно, таким чином з'єднання буде повернуто до пулу підключення, коли транзакція не буде здійснена. Що ж відбувається тоді? JDBC зберігає мовчання, таким чином, це специфічна для впровадження (MySQL відмовляє транзакції, Oracle afair здійснює це). Це також можна налаштувати на рівні Connection Pool (наприклад, C3P0 надає вам таку опцію, відкат за замовчуванням).
  5. Інша справа, коли справа доходить до сплячого режиму, Spring встановлює FlushMode на MANUAL у випадку транзакцій лише для читання, що призводить до інших оптимізацій, таких як відсутність необхідності у брудних чеках.
  6. Ви можете скасувати або чітко встановити рівень ізоляції транзакцій. Це впливає також на транзакції з читанням, оскільки ви чи не хочете читати невмілі зміни, піддаючись фантомним читанням тощо.

Підводячи підсумок - можна піти обома шляхами, але потрібно зрозуміти наслідки.


Спасибо за ответ , якщо так, як?
user93796

Прапор для повторного перегляду фактично встановлений для з'єднання, а не для самої транзакції, і ви не можете отримати доступ до нього через Hibernate просто так. Вам потрібно використовувати підтримку Spring Transaction і використовувати конспекти або конфігурацію транзакцій на основі XML. Тим самим Spring сприймає право власності на з'єднання та управління транзакціями замість Hibernate.
Станіслав Башкирцев

1
Дуже добре пояснено! Ще одна стаття від Марка Річардса досить добре пояснює підводні камені прапора лише для читання в анотації про трансакцію - ibm.com/developerworks/java/library/j-ts1/index.html .
Махеш

48

Усі висловлювання бази даних виконуються в контексті фізичної транзакції, навіть коли ми не заявляємо прямо межі транзакції (BEGIN / COMMIT / ROLLBACK).

Якщо ви не декларуєте явні межі транзакцій, то кожне твердження доведеться виконувати в окремій транзакції ( autocommitрежимі). Це навіть може призвести до відкриття та закриття одного з'єднання на оператор, якщо ваше оточення не може мати справу з прив'язкою з'єднання за потоком.

Якщо оголосити послугу такою @Transactional, ви отримаєте одне з'єднання протягом усієї тривалості транзакції, і всі оператори будуть використовувати це єдине з'єднання для ізоляції. Це краще, ніж спочатку не використовувати явні транзакції.

У великих програмах у вас може бути багато одночасних запитів, і зниження швидкості запитів на отримання з'єднання з базою даних безумовно покращить вашу загальну ефективність програми.

JPA не примушує операцій з операціями читання. Тільки записи, які закінчуються, кидають необхідну виняток транзакції, якщо ви забудете запустити контекст транзакції. Тим не менш, завжди краще оголошувати межі транзакцій навіть для транзакцій лише для читання (навесні @Transactionalдозволяє позначити транзакції лише для читання, що має велику перевагу від ефективності).


1
"... тоді кожне твердження доведеться виконати окремою транзакцією". Контейнер не проводить пакетну обробку автоматично?
Араш

Пакетна обробка призначена для модифікації, а не для читання даних. І навіть так, пакетне використання JDBC не використовується за замовчуванням при використанні JPA та Hibernate.
Влад

1
Дякую Владу. Я прочитав деякі ваші статті. Вони справді корисні.
Араш

Цей stackoverflow.com/q/34797480/179850, здається, трохи суперечить вашому твердженню, що трансакції лише для читання мають велику користь. Принаймні, це не виглядає так у контексті сплячого.
німай

Ні, це не так. Йдеться про налаштування лише для читання, тоді як моє - про уникнення автоматичної фіксації.
Влад Михальча

17

Операції дійсно ставлять блокування в базу даних - хороші двигуни бази даних обробляють одночасно блокування розумними способами - і корисні при використанні лише для читання, щоб гарантувати, що жодна інша транзакція не додає даних, які роблять ваш погляд непослідовним. Ви завжди хочете зробити транзакцію (хоча іноді розумно налаштовувати рівень ізоляції, краще не робити цього для початку); якщо ви ніколи не пишете в БД під час транзакції, і здійснення, і повернення транзакції виходять однаковими (і дуже дешевими).

Тепер, якщо вам пощастило, а ваші запити до БД такі, що ORM завжди відображає їх на єдині SQL запити, ви можете піти без явних транзакцій, спираючись на вбудовану поведінку автокомісії DB, але ORM - це досить складна система тому покладатися на таку поведінку зовсім не безпечно, якщо ви не займетеся набагато більшою роботою, перевіряючи, чим реально займається реалізація. Записати явні межі транзакцій набагато простіше правильно (особливо якщо ви можете це зробити за допомогою AOP або якоїсь подібної методики, керованої ORM; я думаю, що з Java 7 можна використовувати і тест-ресурси).


14

Неважливо, читаєте ви чи ні, база даних все ще повинна відслідковувати ваш набір результатів, оскільки інші клієнти бази даних можуть захотіти записати дані, які змінили б ваш набір результатів.

Я бачив несправні програми для вбивства величезних систем баз даних, тому що вони просто читають дані, але ніколи не здійснюють, змушуючи рости журнал транзакцій, оскільки БД не може випустити дані транзакцій перед COMMIT або ROLLBACK, навіть якщо клієнт нічого не робив годинами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.