Предисловие
Spring Определяет 7 типов поведения распространения транзакций на границе раздела TransactionDefinition. Поведение распространения транзакций - это функция улучшения транзакций, уникальная для структуры пружины, и она не принадлежит к поведению базы данных фактического поставщика транзакции. Это мощный набор инструментов, который Spring предоставляет нам, и использование линий распространения транзакций может предоставить много удобств для наших усилий по разработке. Но у людей есть много недоразумений по этому поводу, и вы, должно быть, слышали слухи о том, что «бизнес -бизнес по обслуживанию лучше всего не быть вложенным». Чтобы правильно использовать инструменты, вы должны сначала понять инструменты. В этой статье подробно представлены семь поведений распространения транзакций и представлены основные примеры кода контента.
Основные понятия
1. Что такое поведение общения транзакций?
Поведение распространения транзакций используется для описания того, как транзакции распространяются, когда методы, модифицированные определенным поведением распространения транзакций, вложены в другой метод.
Используйте псевдокод, чтобы объяснить:
public void methoda () {methodb (); // dosomething} @transaction (Propagation = xxx) public void methodb () {// dosomething} Метод methodA() в коде вызывает метод methodB() в вложенном вложенном виде, а поведение распространения транзакции methodB() определяется настройкой @Transaction(Propagation=XXX) . Здесь следует отметить, что methodA() не запускает транзакцию, и метод изменения определенного поведения распространения транзакции не должен вызывать в периферическом методе запуска транзакции.
2. Семь поведений распространения транзакций весной
| Тип поведения распространения транзакций | иллюстрировать |
|---|---|
| PREGAGATION_REQUID | Если в настоящее время нет транзакции, создайте новую транзакцию, и если уже есть транзакция, добавьте ее в транзакцию. Это самый распространенный выбор. |
| Распространение_SUPPORTS | Поддерживает текущую транзакцию, и если в настоящее время нет транзакции, она будет выполнена не транзакционным образом. |
| Распространение | Используйте текущую транзакцию и добавьте исключение, если в настоящее время нет транзакции. |
| Propagation_Requires_New | Создайте новую транзакцию. Если транзакция в настоящее время существует, приостановите текущую транзакцию. |
| Propagation_not_supported | Выполнять операции не транзакционным образом, и если в настоящее время существует транзакция, текущая транзакция приостановлена. |
| Propagation_never | Выполняется не транзакционным способом и бросает исключение, если в настоящее время существует транзакция. |
| Распространять_nested | Если транзакция в настоящее время существует, она выполняется в пределах вложенной транзакции. Если в настоящее время нет транзакции, выполните операцию, аналогичную Propagation_Required. |
Определение очень простое и легко понять. Давайте перейдем в раздел теста кода, чтобы проверить, является ли наше понимание правильным.
Проверка кода
Код в этой статье представлен в двух слоях в традиционной трехслойной структуре, а именно в сервисе и слое DAO. Весна отвечает за инъекцию зависимости и управление транзакциями аннотации. Уровень DAO реализован Mybatis. Вы также можете использовать любой любимый метод, такой как Hibernate, JPA, JDBCTemplate и т. Д. База данных использует базу данных MySQL, и вы также можете использовать любую базу данных с поддержкой транзакции, которая не повлияет на результаты проверки.
Сначала мы создаем две таблицы в базе данных:
пользователь1
Создать таблицу `user1` (` id` integer unsigned not null auto_increment, `name` varchar (45), а не null default '', первичный ключ (` id`)) engine = innodb;
пользователь2
Создать таблицу `user2` (` id` integer unsigned not null auto_increment, `name` varchar (45), а не null default '', первичный ключ (` id`)) engine = innodb;
Затем напишите соответствующий код слоя бобов и DAO:
Пользователь1
открытый класс user1 {private Integer Id; Приватное название строки; // Получить и установить методы опущены ...}Пользователь2
открытый класс user2 {private Integer Id; Приватное название строки; // Получить и установить методы опущены ...}User1mapper
public interface user1mapper {int insert (user1 record); User1 selectByPrimaryKey (INTEGER ID); // другие методы опущены ...}User2mapper
public interface user2mapper {int insert (user2 record); User2 selectByPrimaryKey (INTEGER ID); // другие методы опущены ...}Наконец, конкретный код проверки реализован уровнем службы, и мы перечислим его в следующих ситуациях.
1.Propagation_Required
Мы добавляем Propagation.REQUIRED атрибуты в соответствующие методы пользователя1Service и user2service.
Метод пользователя1Service:
@Servicepublic class user1serviceimpl реализует user1service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.Required) public void AddRequired (user1) {user1mapper.insert (пользователь); }}Метод пользователя2Service:
@Servicepublic class user2serviceimpl реализует user2service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.Required) public void AddRequired (user2 user) {user2mapper.insert (user); } @Override @Transactional (Propagation = Propagation.Required) public void AddRequireDException (user2 user) {user2mapper.insert (user); бросить новый runtimeexception (); }} 1.1 Сцена 1
Этот сценарий периферийный метод не включает транзакции.
Метод проверки 1:
@Override public void notTransaction_exception_required_required () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequired (user2); бросить новый runtimeexception (); }Метод проверки 2:
@Override public void notTransaction_Required_required_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiredException (user2); }Выполнить методы проверки отдельно, и результаты:
Анализ результатов метода проверки база данных серийных номеров
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Чжан Сан» и «Ли Си» оба вставлены. | Периферический метод не начал транзакцию, и вставка методов «Чжан Сан» и «Ли си» работает независимо в их собственных транзакциях. Аномальный периферический метод не влияет на внутреннюю вставку методов «Zhang San» и «li Si». |
| 2 | «Zhang San» вставлен, но «Li Si» не вставлен. | Периферический метод не имеет транзакций, и методы вставки «Zhang San» и «li Si» работают независимо в их собственных транзакциях, поэтому вставка метода «li si» только откатится от метода «li si» и вставка метода «Zhang San» не будет повлиять. |
Вывод: с помощью этих двух методов мы доказываем, что внутренний метод, измененный путем распространения.
1.2 Сцена 2
Периферический метод запускает транзакцию, которая является сценарием с относительно высокой скоростью использования.
Метод проверки 1:
@Override @Transactional (Propagation = Propagation.Required) public void transaction_exception_required_required () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequired (user2); бросить новый runtimeexception (); }Метод проверки 2:
@Override @Transactional (Propagation = Propagation.Required) public void transaction_required_required_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiredException (user2); }Метод проверки 3:
@TransActional @Override public void transaction_required_required_exception_try () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); try {user2service.addrequiredException (user2); } catch (Exception e) {System.out.println ("Метод ROLLBACK"); }}Выполнить методы проверки отдельно, и результаты:
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Чжан Сан» и «Ли Си» не были вставлены. | Периферический метод запускает транзакцию, внутренний метод соединяет транзакцию периферического метода, периферический метод откатается назад, и внутренний метод также необходимо откатить назад. |
| 2 | «Чжан Сан» и «Ли Си» не были вставлены. | Периферический метод открывает транзакцию, внутренний метод добавляет транзакцию периферического метода, внутренний метод бросает откат исключения, а периферический метод воспринимает исключение, вызывая общую транзакцию в откат. |
| 3 | «Чжан Сан» и «Ли Си» не были вставлены. | Периферический метод открывает транзакцию, внутренний метод соединяет транзакцию периферического метода, а внутренний метод бросает откат исключения. Даже если метод пойман и не воспринимается периферическим методом, вся транзакция все еще откатится. |
Вывод: вышеуказанные экспериментальные результаты показывают, что когда периферический метод открывает транзакцию, внутренние методы, модифицированные Propagation.REQUIRED . Все внутренние методы и периферические методы, модифицированные Propagation.REQUIRED . Пока один метод откатится назад, вся транзакция будет отказана назад.
2.Propagation_Requires_New
Мы добавляем атрибут Propagation.REQUIRES_NEW .
Метод пользователя1Service:
@Servicepublic class user1serviceimpl реализует user1service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.Requires_New) public void addRequiresnew (user1 user) {user1mapper.insert (user); } @Override @Transactional (Propagation = Propagation.Required) public void addRequired (user1 user) {user1mapper.insert (user); }}Метод пользователя2Service:
@Servicepublic class user2serviceimpl реализует user2service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.Requires_New) public void addRequiresnew (user2 user) {user2mapper.insert (user); } @Override @Transactional (Propagation = Propagation.Requires_New) public void AddRequiresNewException (user2 user) {user2mapper.insert (user); бросить новый runtimeexception (); }} 2.1 Сцена 1
Периферический метод не включает транзакции.
Метод проверки 1:
@Override public void notTransaction_exception_Requiresnew_requiresnew () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequiresnew (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiresnew (user2); бросить новый runtimeexception (); }Метод проверки 2:
@Override public void notTransAction_Requiresnew_Requiresnew_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequiresnew (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiresnewexception (user2); }Выполнить методы проверки отдельно, и результаты:
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Zhang San» вставлен, и вставлен «Li Si». | Периферический метод не имеет транзакций. Вставка методов «Zhang San» и «li Si» работает независимо в их собственных транзакциях. Отказ исключения периферического метода не повлияет на внутренний метод. |
| 2 | «Zhang San» вставлен, «Li Si» не вставлен | Периферический метод не запускает транзакцию. Вставка метода «Zhang San» и вставка метода «li Si» начинает свои собственные транзакции соответственно. Вставка метода «li si» бросает откат исключения, а другие транзакции не затронуты. |
Вывод: с помощью этих двух методов мы доказываем, что внутренний метод, измененный с помощью Propagation.REQUIRES_NEW вновь запустит свои собственные транзакции, а открытые транзакции не зависят друг от друга и не мешают друг другу.
2.2 Сцена 2
Периферический метод запускает транзакцию.
Метод проверки 1:
@Override @Transactional (Propagation = Propagation.Required) public void transaction_exception_required_requiresnew_requiresnew () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiresnew (user2); User2 user3 = new user2 (); user3.setname ("wang wu"); user2service.addrequiresnew (user3); бросить новый runtimeexception (); }Метод проверки 2:
@Override @Transactional (Propagation = Propagation.Required) public void transaction_Required_requiresnew_requiresnew_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiresnew (user2); User2 user3 = new user2 (); user3.setname ("wang wu"); user2service.addrequiresnewexception (user3); }Метод проверки 3:
@Override @Transactional (Propagation = Propagation.Required) public void Transaction_Required_Requiresnew_requiresnew_exception_try () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addrequired (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addrequiresnew (user2); User2 user3 = new user2 (); user3.setname ("wang wu"); try {user2service.addrequiresnewexception (user3); } catch (Exception e) {System.out.println ("Rollingback"); }}Выполнить методы проверки отдельно, и результаты:
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Чжан Сан» не был вставлен, «Ли Си» был вставлен, и был вставлен «Ван Ву». | Периферический метод запускает транзакцию, вводит транзакцию метода «Zhang San» и периферический метод, вставляет метод «li Si» и метод «Wang wu» соответственно в независимую недавно созданную транзакцию. Периферический метод бросает исключение и откатается только на ту же транзакцию, что и периферический метод, поэтому метод вставки метода «Zhang San» откатится назад. |
| 2 | «Чжан Сан» не был вставлен, «Ли Си» был вставлен, и «Ван Ву» не был вставлен. | Периферический метод запускает транзакцию, вставляет транзакцию метода «Zhang San» и периферический метод, вставляет метод «li Si» и метод «Wang wu» в независимых новых транзакциях. Когда вставлен метод «Wang Wu», транзакция, которая вставляется в метод «Wang Wu», откатается. Исключение продолжает быть брошено и воспринимается периферийным методом. Транзакция периферического метода также откатается, поэтому метод «Zhang San» также откатается. |
| 3 | «Zhang San» вставлен, «Li Si» вставляется, а «Wang Wu» не вставлен. | Периферический метод запускает транзакцию, вставляет транзакцию метода «Zhang San» и периферический метод, вставляет метод «li Si» и метод «Wang wu» в независимых новых транзакциях. Метод «Ван Ву» вставлен, и транзакция, которая вставляет метод «Ван Ву», откатится назад. Исключение поймано и не будет воспринято периферическим методом. Транзакция периферического метода не откатится, поэтому вставка метода «Zhang San» успешно вставлена. |
Вывод: когда периферический метод открывает транзакцию, внутренний метод, измененный путем Propagation.REQUIRES_NEW все еще откроет независимые транзакции отдельно, а также не зависит от транзакций внешнего метода. Внутренний метод, внутренний метод и транзакции внешнего метода не зависят друг от друга и не мешают друг другу.
3.Propagation_nested
Мы добавляем Propagation.NESTED атрибуты к соответствующим методам пользователя1Service и user2service.
Метод пользователя1Service:
@Servicepublic class user1serviceimpl реализует user1service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.nestess) public void AddNestest (user1) {user1mapper.insert (user); }}Метод пользователя2Service:
@Servicepublic class user2serviceimpl реализует user2service {// Опустить другие ... @Override @Transactional (Propagation = Propagation.nested) public void AddNestest (user2) {user2mapper.insert (user); } @Override @Transactional (Propagation = Propagation.nested) public void addnestEdexception (user2 user) {user2mapper.insert (user); бросить новый runtimeexception (); }} 3.1 Сцена 1
Этот сценарий периферийный метод не включает транзакции.
Метод проверки 1:
@Override public void notTransaction_exception_nestest_nestest () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addnated (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addntest (user2); бросить новый runtimeexception (); }Метод проверки 2:
@Override public void notTransaction_nestest_nestest_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addnated (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addnestexexception (user2); }Выполнить методы проверки отдельно, и результаты:
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Чжан Сан» и «Ли Си» оба вставлены. | Периферический метод не начал транзакцию, и вставка методов «Чжан Сан» и «Ли си» работает независимо в их собственных транзакциях. Аномальный периферический метод не влияет на внутреннюю вставку методов «Zhang San» и «li Si». |
| 2 | «Zhang San» вставлен, но «Li Si» не вставлен. | Периферический метод не имеет транзакций, и методы вставки «Zhang San» и «li Si» работают независимо в их собственных транзакциях, поэтому вставка метода «li si» только откатится от метода «li si» и вставка метода «Zhang San» не будет повлиять. |
Вывод: с помощью этих двух методов мы доказываем, что Propagation.NESTED и Propagation.REQUIRED имеют одинаковые функции, когда периферический метод не открывает транзакцию. Модифицированные внутренние методы снова начнут свои собственные транзакции, а открытые транзакции не зависят друг от друга и не мешают друг другу.
3.2 Сцена 2
Периферический метод запускает транзакцию.
Метод проверки 1:
@TransActional @Override public void transaction_exception_nest_nestest () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addnated (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addntest (user2); бросить новый runtimeexception (); }Метод проверки 2:
@TransActional @Override public void transaction_nestest_nest_exception () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addnated (user1); User2 user2 = new user2 (); user2.setname ("li si"); user2service.addnestexexception (user2); }Метод проверки 3:
@TransActional @Override public void transaction_nestest_nest_exception_try () {user1 user1 = new user1 (); user1.setname ("Zhang San"); user1service.addnated (user1); User2 user2 = new user2 (); user2.setname ("li si"); try {user2service.addnestEdexception (user2); } catch (Exception e) {System.out.println ("Метод ROLLBACK"); }}Выполнить методы проверки отдельно, и результаты:
| Метод проверки серийный номер | Результаты базы данных | Анализ результатов |
|---|---|---|
| 1 | «Чжан Сан» и «Ли Си» не были вставлены. | Периферический метод запускает транзакцию, а внутренняя транзакция является субтеробежной периферической транзакции. Периферический метод откатится назад, и внутренний метод также должен быть откат назад. |
| 2 | «Чжан Сан» и «Ли Си» не были вставлены. | Периферический метод запускает транзакцию, а внутренняя транзакция является субтеробежной периферической транзакции. Внутренний метод бросает откат исключения, и периферический метод воспринимает исключение, вызывая общую транзакцию для отката. |
| 3 | «Zhang San» вставлен, и «Li Si» не вставлен. | Периферический метод запускает транзакцию, а внутренняя транзакция является субтеробежной периферической транзакции. Вставьте внутренний метод «Zhang San», чтобы бросить исключение, и дочерняя транзакция может быть отброшена отдельно. |
Вывод: приведенные выше результаты теста показывают, что когда периферический метод открывает транзакцию, внутренний метод, модифицированный с помощью Propagation.NESTED Нарученный принадлежит к субразированию внешней транзакции. Периферическая основная транзакция откатится назад, и субтуда должна отказаться. Внутренняя субразиция может быть отброшена отдельно, не влияя на периферическую основную транзакцию и другие субперранзакции.
4. Сходство и сходство необходимого, требуется_new, вложенные
Из сравнения «1.2 сцена 2» и «3.2 сцена 2» мы можем увидеть:
Внутренние методы, модифицированные вложенными и необходимыми, являются оба транзакций периферических методов. Если периферический метод бросает исключение, транзакции обоих методов будут откатаются. Однако необходимые соединения транзакций периферических методов, поэтому он принадлежит к той же транзакции, что и периферические транзакции. После того, как требуемая транзакция бросает исключение и откатится назад, транзакции периферических методов также будут откатываться. Вложенное является субтешн-транзакцией периферического метода и имеет отдельную точку сохранения, поэтому вложенный метод бросает исключение и откатывается, что не повлияет на транзакцию периферического метода.
Из сравнения «2,2 сцена 2» и «3.2 сцена 2» мы можем увидеть:
Как вложенные, так и требуемые_new могут отменить транзакции внутренних методов, не влияя на транзакции периферических методов. Однако, поскольку вложенная вложенная транзакция, после того, как периферический метод откатается назад, суб-транзакции, которые являются периферическими транзакциями метода, также будут откатываться назад. TRESS_NEW реализован путем открытия новой транзакции. Внутренние транзакции и периферические транзакции являются двумя транзакциями. Откат периферической транзакции не повлияет на внутренние транзакции.
5. Другое поведение распространения транзакций
Ввиду проблемы длины статьи, тесты других поведений распространения транзакций не будут описаны здесь. Заинтересованные читатели могут искать соответствующий тестовый код и объяснения результатов в исходном коде. Портал: https: //github.com/tmtse/tran ...
Слушания использования моделирования
После того, как мы применим их в нашей реальной работе? Позвольте мне привести вам пример:
Предположим, у нас есть зарегистрированный метод, в котором называется метод добавления точек. Если мы хотим добавить точки, чтобы не повлиять на процесс регистрации (то есть откат не удалось добавить точки не может сделать откат метода регистрации), мы напишем это:
@Service public class userserviceimpl реализует userservice {@transactional public void Register (Пользователь пользователя) {try {memberhippointservice.addpoint (точка); } catch (Exception e) {// omit ...} // oll ...} // Опустить ...} Мы также предусматриваем, что сбой регистрации повлияет на метод addPoint() (откат метода регистрации также требует отката), поэтому метод addPoint() должен быть реализован таким образом:
@Service public class kenhippointserviceimpl реализует участники kenhippointservice {@transactional (Propagation = Propagation.nested) public void AddPoint (point) {try {recordservice.addrecord (запись записи); } catch (Exception e) {// omit ...} // oll ...} // Опустить ...} Мы заметили, что метод addRecord() addPoint() , который используется для записи журналов. Его реализация заключается в следующем:
@Service Public Class RecorderServiceImpl реализует recordservice {@Transactional (Propagation = Propagation.not_Supported) public void AddRecord (запись записи) {// olmit ...} // Опустить ...} Мы заметили propagation = Propagation.NOT_SUPPORTED в методе addRecord() , поскольку оно не является точным для журнала, и один может быть более или менее, поэтому метод addRecord() и метод периферической addPoint() не вызовет метод addRecord() , а метод addRecord() addPoint() не будет влиять на метод выполнения.
В этом примере я считаю, что у каждого есть более интуитивное понимание использования поведения в связи с транзакцией. Сочетание различных атрибутов действительно может сделать нашу бизнес -реализацию более гибкой и разнообразной.
в заключение
Благодаря вышеупомянутому введению, я считаю, что у каждого более глубокое понимание поведения общения с весенней транзакцией, и я надеюсь, что ваша ежедневная работа по развитию будет полезна.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.