Пролетни транзакционни съвети и грешки - блогът на Анатолий Корсаков

В този пост ще събера най-добрите практики за използване на Spring Transactional.

Сервиз или DAO?

  • Задайте анотацията @Transactional на слоя Service, а не на DAO слоя. Сервизните зърна могат да използват множество DAO, като спазват ACID при една и съща транзакция. В противен случай, ако само DAO дефинира механизъм на транзакция, тогава сервизните компоненти ще увеличат разходите за създаване на множество транзакции за концептуално групирани операции, да не говорим за непостоянното състояние на данните, което рискуваме да получим.

  • В този момент, продължавайки мисълта от предишната, можем да зададем @Transactional (propagation = Propagation.MANDATORY) на ниво клас в нашите DAO, като по този начин принуждаваме потребителите на нашите DAO да инициират управление на транзакции.
  • Трябва да знаете поведението по подразбиране на @Transactional анотацията и да не я използвате сляпо. А именно, освен ако не е изрично посочено, нивото на разпространение ще бъде зададено на Propagation.REQUIRED, което означава да се използва текущата транзакция, в противен случай се създава нова; изолацията ще бъде зададена на стойност Isolation.DEFAULT, тази стойност се определя от основната база данни (по подразбиране за много бази данни тази стойност е Isolation.READ_COMMITED); флагът readOnly е изключен по подразбиране; rollbackFor може да се зададе с клас Throwable, но бъдете внимателни: по подразбиране връщането се извършва само когато е хвърлено RuntimeException (ако този параметър не е зададен).
  • Бъдете внимателни с флага readOnly. Въпреки че @Transactional (readOnly = true, propagation = Propagation.REQUIRED) ще хвърли изключение, когато се опитва да изпълни команда за вмъкване/актуализиране чрез JDBC в транзакция, може да има неочаквано поведение при опит за вмъкване/актуализиране чрез ORM, където операцията ще се извърши крадешком и ще извърши транзакцията успешно ... В ORM среда този флаг трябва да се използва заедно с Propagation.SUPPORTS. В този случай няма да платим разходите за създаване на нова транзакция в проста операция за извличане. Или дори помислете да се отървете от управлението на транзакции за операции SELECT.
  • Бъдете внимателни, когато използвате Propagation.REQUIRES_NEW не на най-високото ниво на транзакции. Това може да доведе до множество проблеми. Всеки път, когато нова основна транзакция се увива около този аспект, в случаите, когато множество транзакции с REQUIRES_NEW са включени в рамките на един метод за транзакционна услуга, могат да възникнат проблеми със загубата на данни. От друга страна, не е забранено използването на анотации на транзакционен метод от най-високо ниво, което всъщност е същото поведение като разпространението по подразбиране.

Spring автоматично връща транзакции за непроверени (Runtime) изключения

Когато възникне изключение по време на изпълнение, Spring маркира текущата транзакция за връщане назад.

Може би най-объркващата част от такива възстановявания е да видим това съобщение „UnexpectedRollbackException: Транзакцията е върната назад, защото е маркирана като само откат“ .