Сводка транзакций Spring из более чем 7000 слов уже здесь! Я полный!

Spring
"

Эта статья была включена в проект Github 75k+ Star Java JavaGuide. Адрес проекта JavaGuide:GitHub.com/snail Climb/…. Настоятельно рекомендуется, чтобы друзья, которые изучают Java, посмотрели!

Всем привет, я Гид, как обещал читателям в предыдущем абзаце.Весенние транзакцииРезюме анализа, наконец, здесь. Эта часть контента более важна, будь то работа или собеседование, но в Интернете относительно мало хороших ссылок. Связанное чтение: версия V2.0«JavaGuide Interview Assault Edition» уже здесь! А вот и онлайн-версия для чтения!

Если в этой статье что-то не так или что-то нужно улучшить, пожалуйста, помогите указать на это! Гид брат очень благодарен!

1. Что такое транзакция?

Транзакция — это логический набор операций, либо все операции, либо ни одна из них.

Брат Гид: Каждый должен уметь повторять приведенное выше предложение Позвольте мне рассказать об этом в сочетании с нашим ежедневным реальным развитием.

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

 public void savePerson() {
  personDao.save(person);
  personDetailDao.save(personDetail);
 }

Кроме того, важно отметить, что:Может ли транзакция вступить в силу или нет, является ключом к тому, поддерживает ли механизм базы данных транзакцию. Например, обычно используемая база данных MySQL использует поддержку транзакций по умолчанию.innodbдвигатель. Однако, если вы измените механизм базы данных наmyisam, то программа больше не поддерживает транзакции!

В качестве примера перевода часто используется самая классическая транзакция. Если Сяомин хочет перевести 1000 юаней Сяохуну, этот перевод будет включать две ключевые операции:

  1. Уменьшите баланс Сяо Мина на 1000 юаней.

  2. Увеличьте баланс Сяохун на 1000 юаней.

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

public class OrdersService {
 private AccountDao accountDao;

 public void setOrdersDao(AccountDao accountDao) {
  this.accountDao = accountDao;
 }

  @Transactional(propagation = Propagation.REQUIRED,
                isolation = Isolation.DEFAULT, readOnly = false, timeout = -1)
 public void accountMoney() {
    //小红账户多1000
  accountDao.addMoney(1000,xiaohong);
  //模拟突然出现的异常,比如银行中可能为突然停电等等
    //如果没有配置事务管理的话会造成,小红账户多了1000而小明账户没有少钱
  int i = 10 / 0;
  //小王账户少1000
  accountDao.reduceMoney(1000,xiaoming);
 }
}

Кроме того, в основе транзакций лежат четыре характеристики ACID транзакций базы данных.Давайте кратко рассмотрим их ниже.

2. Разбираетесь ли вы в свойствах вещей (АКИД)?

  • Атомарность:Транзакция является наименьшей единицей выполнения и не допускает разделения. Атомарность транзакций гарантирует, что действия либо завершатся, либо вообще ничего не сделают;
  • последовательность:До и после выполнения транзакции данные остаются согласованными;
  • Изоляция:При одновременном доступе к базе данных транзакции пользователя не мешают другим транзакциям, то есть при одновременном выполнении нескольких транзакций выполнение одной транзакции не должно влиять на выполнение других транзакций;
  • Упорство:После совершения транзакции. Его изменения данных в базе данных являются постоянными, и даже если база данных выйдет из строя, это не должно на нее повлиять.

3. Подробно расскажите о поддержке транзакций в Spring

Напомню еще раз: поддерживает ли ваша программа транзакции, в первую очередь зависит от базы данных.Например, если вы используете MySQL, если вы выбираете движок innodb, поздравляю, вы можете поддерживать транзакции. Однако, если ваша база данных MySQL использует движок myisam, извините, он не поддерживает транзакции из корня.

Вот еще один очень важный пункт знаний:Как MySQL гарантирует атомарность?

Мы знаем, что если мы хотим обеспечить атомарность транзакции, нам нужно выполнять операции над уже выполненными операциями при возникновении исключения.откат, в MySQL механизм восстановления черезЖурнал отката (журнал отмены)Реализовано, все изменения, сделанные транзакцией, будут сначала записываться в журнал отката, а затем будут выполняться соответствующие операции. Если во время выполнения возникает исключение, мы напрямую используемжурнал откатаИнформацию в данных можно откатить на то, что было до модификации! Кроме того, журнал отката сохраняется на диск перед данными. Это гарантирует, что даже если база данных внезапно выйдет из строя, когда пользователь снова запустит базу данных, база данных все равно сможет выполнить откат ранее незавершенных транзакций, запросив журнал отката.

3.1 Spring поддерживает два способа управления транзакциями

1) Программное управление транзакциями

пройти черезTransactionTemplateилиTransactionManagerРучное управление транзакциями редко используется в практических приложениях, но вам будет полезно понять принципы управления транзакциями Spring.

использоватьTransactionTemplateПример кода для программного управления транзакциями выглядит следующим образом:

@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

                try {

                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
}

использоватьTransactionManagerПример кода для программного управления транзакциями выглядит следующим образом:

@Autowired
private PlatformTransactionManager transactionManager;

public void testTransaction() {

  TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
          try {
               // ....  业务代码
              transactionManager.commit(status);
          } catch (Exception e) {
              transactionManager.rollback(status);
          }
}

2) Декларативное управление транзакциями

Рекомендуется (наименее инвазивный код), фактически реализуется через АОП (на основе@TransactionalЧаще всего используется метод полной аннотации).

использовать@TransactionalПример кода аннотации для управления транзакциями выглядит следующим образом:

@Transactional(propagation=propagation.PROPAGATION_REQUIRED)
public void aMethod {
  //do something
  B b = new B();
  C c = new C();
  b.bMethod();
  c.cMethod();
}

3.2 Введение в интерфейс управления транзакциями Spring

В среде Spring три наиболее важных интерфейса, связанных с управлением транзакциями, следующие:

  • PlatformTransactionManager: (платформа) менеджер транзакций, сердце стратегии транзакций Spring.
  • TransactionDefinition: Информация об определении транзакции (уровень изоляции транзакции, поведение распространения, время ожидания, только для чтения, правила отката).
  • TransactionStatus: Состояние выполнения транзакции.

мы можем поставитьPlatformTransactionManagerИнтерфейс можно рассматривать как менеджер верхнего уровня транзакции, в то время какTransactionDefinitionиTransactionStatusЭти два интерфейса можно рассматривать как описания вещей.

PlatformTransactionManagerбудет основываться наTransactionDefinitionТакие определения, как тайм-аут транзакции, уровень изоляции, поведение распространения и т. д., используются для управления транзакциями, в то время какTransactionStatusИнтерфейс предоставляет некоторые методы для получения соответствующего состояния транзакции, например, является ли она новой транзакцией, можно ли ее откатить и т. д.

3.2.1. PlatformTransactionManager: интерфейс управления транзакциями

Spring не управляет транзакциями напрямую, но предоставляет различные менеджеры транзакций.. Интерфейс менеджера транзакций Spring:PlatformTransactionManager.

Через этот интерфейс Spring предоставляет различные платформы, такие как JDBC (DataSourceTransactionManager), Спящий режим(HibernateTransactionManager), JPA(JpaTransactionManager) и т. д. предоставляют соответствующий менеджер транзакций, но конкретная реализация зависит от каждой платформы.

PlatformTransactionManagerКонкретная реализация интерфейса выглядит следующим образом:

PlatformTransactionManagerВ интерфейсе определены три метода:

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface PlatformTransactionManager {
    //获得事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

Еще одно слово здесь. Зачем определять или абстрагироватьсяPlatformTransactionManagerЧто с этим интерфейсом?

Основная причина заключается в том, чтобы абстрагировать поведение управления транзакциями, а затем реализовать его на разных платформах, чтобы мы могли гарантировать неизменность предоставляемого извне поведения, что нам удобно расширять. Я поделился некоторое время назад:«Почему мы используем интерфейсы?»

3.2.2 TransactionDefinition: Атрибуты транзакции

Интерфейс менеджера транзакцийPlatformTransactionManagerпройти черезgetTransaction(TransactionDefinition definition)метод для получения транзакции, параметры в этом методеTransactionDefinitionclass , который определяет некоторые основные атрибуты транзакции.

Так что жеСвойства транзакцииШерстяная ткань?

Атрибуты транзакций можно понимать как некоторые базовые конфигурации транзакций, описывающие, как политики транзакций применяются к методам.

Атрибуты транзакции включают 5 аспектов:

TransactionDefinitionИнтерфейс определяет 5 методов и некоторые константы, которые представляют свойства транзакции, такие как уровень изоляции, поведение распространения и т. д.

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;
    // 返回事务的传播行为,默认值为 REQUIRED。
    int getPropagationBehavior();
    //返回事务的隔离级别,默认值是 DEFAULT
    int getIsolationLevel();
    // 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
    int getTimeout();
    // 返回是否为只读事务,默认值为 false
    boolean isReadOnly();

    @Nullable
    String getName();
}

3.2.3. TransactionStatus: статус транзакции

TransactionStatusИнтерфейс используется для записи состояния транзакции.Интерфейс определяет набор методов для получения или оценки соответствующей информации о состоянии транзакции.

PlatformTransactionManager.getTransaction(…)метод возвращаетTransactionStatusобъект.

Содержимое интерфейса TransactionStatus следующее:

public interface TransactionStatus{
    boolean isNewTransaction(); // 是否是新的事物
    boolean hasSavepoint(); // 是否有恢复点
    void setRollbackOnly();  // 设置为只回滚
    boolean isRollbackOnly(); // 是否为只回滚
    boolean isCompleted; // 是否已完成
}

3.3 Подробное объяснение атрибутов транзакции

В реальном развитии бизнеса все обычно используют@TransactionalАннотация для открытия сделки, многие не знают, что означают параметры в этом параметре и в чем польза. Чтобы лучше использовать управление транзакциями в своем проекте, настоятельно рекомендуется внимательно прочитать следующее содержимое.

3.3.1 Поведение при распространении транзакций

Поведение распространения транзакций заключается в решении проблемы транзакций при вызове друг друга между методами бизнес-уровня..

Когда метод транзакции вызывается другим методом транзакции, вы должны указать, как транзакция должна распространяться. Например: метод может продолжать выполняться в существующей транзакции или может запускать новую транзакцию и выполняться в своей собственной транзакции.

Например!

Мы в классе АaMethod()Метод класса B называетсяbMethod()метод. В настоящее время возникает проблема транзакции вызова друг друга между методами бизнес-уровня. если нашbMethod()Если возникает исключение и его необходимо откатить, как настроить поведение распространения транзакций, чтобыaMethod()Тоже откатиться? В настоящее время требуется знание поведения распространения транзакций.Если вы этого не знаете, вы должны хорошенько присмотреться.

Class A {
    @Transactional(propagation=propagation.xxx)
    public void aMethod {
        //do something
        B b = new B();
        b.bMethod();
    }
}

Class B {
    @Transactional(propagation=propagation.xxx)
    public void bMethod {
       //do something
    }
}

существуетTransactionDefinitionОпределение включает следующие константы, которые представляют поведение распространения:

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    ......
}

Однако для удобства Spring соответственно определяет класс перечисления:Propagation

package org.springframework.transaction.annotation;

import org.springframework.transaction.TransactionDefinition;

public enum Propagation {

 REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

 SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

 MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

 REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

 NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

 NEVER(TransactionDefinition.PROPAGATION_NEVER),

 NESTED(TransactionDefinition.PROPAGATION_NESTED);


 private final int value;

 Propagation(int value) {
  this.value = value;
 }

 public int value() {
  return this.value;
 }

}

Возможные значения для правильного поведения распространения транзакций следующие::

1.TransactionDefinition.PROPAGATION_REQUIRED

Наиболее часто используемое поведение распространения транзакций, которое мы обычно используем@TransactionalИспользование аннотации по умолчанию — это поведение распространения транзакции. Если транзакция уже существует, присоединиться к ней, если текущей транзакции нет, создать новую транзакцию. Это:

  1. Если внешний метод не запускает транзакцию,Propagation.REQUIREDДекорированный внутренний метод заново откроет свою собственную транзакцию, а открытые транзакции не зависят друг от друга и не мешают друг другу.
  2. Если внешний метод запускает транзакцию иPropagation.REQUIREDслова, всеPropagation.REQUIREDИ декорированный внутренний метод, и внешний метод принадлежат одной и той же транзакции.Пока происходит откат одного метода, откатывается вся транзакция.

Например: если у нас есть вышеaMethod()иbMethod()используютсяPROPAGATION_REQUIREDДля поведения распространения оба используют одну и ту же транзакцию, пока один из методов откатывается, вся транзакция откатывается.

Class A {
    @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
    public void aMethod {
        //do something
        B b = new B();
        b.bMethod();
    }
}

Class B {
    @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
    public void bMethod {
       //do something
    }
}

2.TransactionDefinition.PROPAGATION_REQUIRES_NEW

Создайте новую транзакцию и приостановите текущую транзакцию, если есть текущая транзакция. То есть, независимо от того, открывает ли внешний метод транзакцию,Propagation.REQUIRES_NEWДекорированный внутренний метод заново откроет свою собственную транзакцию, а открытые транзакции не зависят друг от друга и не мешают друг другу.

Например: если у нас есть вышеbMethod()использоватьPROPAGATION_REQUIRES_NEWмодификация поведения распространения транзакций,aMethodвсе еще используюPROPAGATION_REQUIREDМодифицированные слова. еслиaMethod()происходит откат исключения,bMethod()не последует откат, т.к.bMethod()Начать независимую транзакцию. но еслиbMethod()Если возникает необработанное исключение, которое удовлетворяет правилам отката транзакции,aMethod()Так же будет откатываться, потому что вызывается исключениеaMethod()Механизм управления транзакциями .

Class A {
    @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
    public void aMethod {
        //do something
        B b = new B();
        b.bMethod();
    }
}

Class B {
    @Transactional(propagation=propagation.REQUIRES_NEW)
    public void bMethod {
       //do something
    }
}

3.TransactionDefinition.PROPAGATION_NESTED:

Если транзакция в настоящее время существует, создайте транзакцию для запуска как вложенную транзакцию текущей транзакции; если текущей транзакции нет, значение эквивалентноTransactionDefinition.PROPAGATION_REQUIRED. Это:

  1. В случае, когда внешний метод не открывает транзакциюPropagation.NESTEDиPropagation.REQUIREDЭффект тот же, измененные внутренние методы будут заново открывать свои собственные транзакции, а открытые транзакции независимы друг от друга и не мешают друг другу.
  2. Если внешний метод запускает транзакцию,Propagation.NESTEDДекорированный внутренний метод принадлежит подтранзакции внешней транзакции, если внешняя основная транзакция откатится, то подтранзакция также будет отброшена, в то время как внутреннюю подтранзакцию можно откатить независимо, не затрагивая внешнюю основную транзакцию. транзакции и другие субтранзакции.

Вот простой пример:

еслиaMethod()Если ты откатишься назад,bMethod()иbMethod2()откатиться назад иbMethod()Откат не вызоветaMethod()иbMethod()откат.

Class A {
    @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
    public void aMethod {
        //do something
        B b = new B();
        b.bMethod();
        b.bMethod2();
    }
}

Class B {
    @Transactional(propagation=propagation.PROPAGATION_NESTED)
    public void bMethod {
       //do something
    }
    @Transactional(propagation=propagation.PROPAGATION_NESTED)
    public void bMethod2 {
       //do something
    }
}

4.TransactionDefinition.PROPAGATION_MANDATORY

Если в данный момент есть транзакция, присоединиться к транзакции; если текущей транзакции нет, сгенерировать исключение. (обязательно: обязательно)

Это редко используется, чтобы не приводить пример.

Если следующие три поведения распространения транзакций настроены неправильно, то транзакция не будет откатана, это не объясняется по сравнению с кейсом и используется редко.

  • TransactionDefinition.PROPAGATION_SUPPORTS: если есть текущая транзакция, присоединиться к транзакции; если текущей транзакции нет, продолжить выполнение в нетранзакционном режиме.
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: Запустить в нетранзакционном режиме, если есть текущая транзакция, приостановить текущую транзакцию.
  • TransactionDefinition.PROPAGATION_NEVER: Работает в нетранзакционном режиме, генерирует исключение, если в данный момент есть транзакция.

Подробнее о поведении распространения транзакций читайте в этой статье:«Это слишком сложно~ Интервьюер попросил меня рассказать о моем понимании поведения распространения транзакций Spring на основе случая. 》

3.3.2 Уровень изоляции транзакции

TransactionDefinitionИнтерфейс определяет пять констант, которые представляют уровень изоляции:

public interface TransactionDefinition {
    ......
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    ......
}

Подобно поведению распространения транзакций, для удобства Spring также определяет класс перечисления соответствующим образом:Isolation

public enum Isolation {

 DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),

 READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),

 READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),

 REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),

 SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);

 private final int value;

 Isolation(int value) {
  this.value = value;
 }

 public int value() {
  return this.value;
 }

}

Ниже я по очереди представлю каждый уровень изоляции транзакций:

  • TransactionDefinition.ISOLATION_DEFAULT: использовать уровень изоляции серверной базы данных по умолчанию, который по умолчанию используется MySQL.REPEATABLE_READУровень изоляции, который Oracle использует по умолчаниюREAD_COMMITTEDуровень изоляции.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: самый низкий уровень изоляции. Этот уровень изоляции используется редко, поскольку позволяет считывать изменения данных, которые еще не были зафиксированы.Может вызвать грязное чтение, фантомное чтение или неповторяющееся чтение.
  • TransactionDefinition.ISOLATION_READ_COMMITTED: позволяет читать данные, которые были зафиксированы параллельными транзакциями,Грязные чтения можно предотвратить, но фантомные или неповторяющиеся чтения все же могут происходить.
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: результаты многократного чтения одного и того же поля согласуются, если данные не изменены его собственной транзакцией.Грязные чтения и неповторяющиеся чтения можно предотвратить, но фантомные чтения все еще могут возникать.
  • TransactionDefinition.ISOLATION_SERIALIZABLE: Самый высокий уровень изоляции, полностью соответствующий уровню изоляции ACID. Все транзакции выполняются одна за другой, так что абсолютно исключена возможность вмешательства между транзакциями, т.е.Этот уровень предотвращает грязные чтения, неповторяемые чтения и фантомные чтения.. Но это серьезно повлияет на производительность программы. Обычно этот уровень также не используется.

Поскольку я обычно больше использую базу данных MySQL, я упомяну ее здесь!

Поддерживаемые по умолчанию уровни изоляции для механизма хранения MySQL InnoDB:REPEATABLE-READ(перечитываемый). мы можем пройтиSELECT @@tx_isolation;команду для просмотра следующим образом:

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+

Здесь следует отметить, что отличие от стандарта SQL заключается в том, что механизм хранения InnoDBREPEATABLE-READ(перечитываемый)Алгоритм Next-Key Lock используется на уровне изоляции транзакций, поэтому он позволяет избежать генерации фантомных операций чтения, что отличается от других систем баз данных (таких как SQL Server). Таким образом, уровень изоляции по умолчанию, поддерживаемый механизмом хранения InnoDB, равенREPEATABLE-READ(перечитываемый)Требования к изоляции транзакций уже могут быть полностью гарантированы, то есть те, которые соответствуют стандарту SQL.SERIALIZABLE(сериализуемый)уровень изоляции.

Поскольку чем ниже уровень изоляции, тем меньше блокировок требует транзакция, поэтому уровень изоляции большинства систем баз данных ниже.READ-COMMITTED(читать коммиты):, но вам нужно знать, что механизм хранения InnoDB использует по умолчаниюREPEATABLE-READ(перечитываемый)Ни о какой потере производительности речи не идет.

Дополнительные сведения об уровнях изоляции транзакций см.

  1. «Одна статья поможет вам легко понять уровень изоляции транзакций (подробная графика и текст)»
  2. Интервьюер: Вы сказали, что знакомы с транзакциями MySQL? Тогда я задам вам 10 вопросов

3.3.3 Свойства времени ожидания транзакции

Так называемый тайм-аут транзакции относится к максимальному времени, разрешенному для выполнения транзакции.Если лимит времени превышен, но транзакция не была завершена, транзакция будет автоматически отменена. существуетTransactionDefinitionВремя ожидания представлено значением int в секундах, а значение по умолчанию равно -1.

3.3.3 Свойства транзакции только для чтения

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface TransactionDefinition {
    ......
    // 返回是否为只读事务,默认值为 false
    boolean isReadOnly();

}

Для транзакций, которые только читают запросы данных, вы можете указать тип транзакции как readonly, то есть транзакции только для чтения. Транзакции только для чтения не требуют изменения данных, и база данных предоставляет некоторые методы оптимизации, которые подходят для использования в методах с несколькими операциями запросов к базе данных.

Многие спросят, зачем мне включать поддержку транзакций для операции запроса данных?

Возьмем в качестве примера MySQL innodb, согласно официальному сайту.Dev.MySQL.com/doc/Furious/…описывать:

"

MySQL включен по умолчанию для каждого вновь установленного соединенияautocommitмодель. В этом режиме каждое сообщение, отправленное на сервер MySQL,sqlОператоры обрабатываются в отдельной транзакции, и транзакция автоматически фиксируется после выполнения и запускается новая транзакция.

Однако, если вы добавите методTransactionalЕсли он аннотирован, этот метод выполняет всеsqlбудет помещен в транзакцию. Если объявлена ​​транзакция только для чтения, база данных оптимизирует ее выполнение и не принесет никаких других преимуществ.

если не добавитьTransactional, каждыйsqlБудет открыта отдельная транзакция, и если данные будут изменены другими транзакциями в середине, последнее значение будет прочитано в режиме реального времени.

Поделитесь ответами других людей об атрибутах транзакции только для чтения:

  1. Если вы выполняете один оператор запроса за раз, нет необходимости включать поддержку транзакций, база данных поддерживает согласованность чтения во время выполнения SQL по умолчанию;
  2. Если вы выполняете несколько операторов запроса одновременно, например, статистический запрос, запрос отчета, в этом сценарии множественный SQL-запрос должен обеспечивать общую согласованность чтения, в противном случае после предыдущего SQL-запроса и до следующего SQL-запроса данные будут другие пользователи изменятся, общий статистический запрос будет иметь противоречивые данные чтения. В это время должна быть включена поддержка транзакций.

3.3.4 Правила отката транзакции

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

Если вы хотите откатить определенный тип исключения, который вы определили, вы можете сделать это:

@Transactional(rollbackFor= MyException.class)

3.4 Подробное объяснение использования аннотации @Transactional

1) @Transactionalсфера действия

  1. метод: Рекомендуется использовать аннотации к методам, но следует отметить, что:Эту аннотацию можно применять только к общедоступным методам, иначе она не вступит в силу.
  2. своего рода: если эта аннотация используется в классе, это означает, что аннотация действительна для всех общедоступных методов в классе.
  3. интерфейс: Не рекомендуется использовать на интерфейсах.

2) @TransactionalОбщие параметры конфигурации

@TransactionalИсходный код аннотации выглядит следующим образом, он содержит конфигурацию основных свойств транзакции:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

 @AliasFor("transactionManager")
 String value() default "";

 @AliasFor("value")
 String transactionManager() default "";

 Propagation propagation() default Propagation.REQUIRED;

 Isolation isolation() default Isolation.DEFAULT;

 int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

 boolean readOnly() default false;

 Class<? extends Throwable>[] rollbackFor() default {};

 String[] rollbackForClassName() default {};

 Class<? extends Throwable>[] noRollbackFor() default {};

 String[] noRollbackForClassName() default {};

}

@TransactionalРезюме общих параметров конфигурации (только огромный список из 5, которые я обычно использую):

Имя свойства инструкция
propagation Поведение транзакции при распространении, значение по умолчанию ТРЕБУЕТСЯ, необязательное значение описано выше.
isolation Уровень изоляции транзакции.Значение по умолчанию — DEFAULT.Необязательные значения описаны выше.
timeout Тайм-аут транзакции, значение по умолчанию равно -1 (нет тайм-аута). Если лимит времени превышен, но транзакция не завершена, транзакция автоматически откатывается.
readOnly Указывает, является ли транзакция доступной только для чтения, значение по умолчанию — false.
rollbackFor Используется для указания типа исключения, которое может инициировать откат транзакции, и можно указать несколько типов исключений.

3)@TransactionalПринцип аннотации сделки

Вопрос, который можно задать, задавая АОП на собеседовании. Просто сказать это!

мы знаем,@TransactionalМеханизм работы основан на АОП, а АОП реализован с использованием динамического прокси. Если целевой объект реализует интерфейс, по умолчанию будет использоваться динамический прокси JDK, если целевой объект не реализует интерфейс, будет использоваться динамический прокси CGLIB.

Еще одно слово:createAopProxy()Метод определяет, использовать ли JDK или Cglib для динамического прокси.Исходный код выглядит следующим образом:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

 @Override
 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
   Class<?> targetClass = config.getTargetClass();
   if (targetClass == null) {
    throw new AopConfigException("TargetSource cannot determine target class: " +
      "Either an interface or a target is required for proxy creation.");
   }
   if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
   }
   return new ObjenesisCglibAopProxy(config);
  }
  else {
   return new JdkDynamicAopProxy(config);
  }
 }
  .......
}

Если класс или открытый метод в классе аннотированы@TransactionalЕсли аннотировать, контейнер Spring создаст для него прокси-класс при запуске, и он будет вызываться@TransactionalКогда аннотированный общедоступный метод действительно вызывается,TransactionInterceptorв классеinvoke()метод. Функция этого метода заключается в том, чтобы открыть транзакцию перед целевым методом.Если во время выполнения метода возникает исключение, транзакция откатывается, и транзакция фиксируется после завершения вызова метода.

"

TransactionInterceptorв классеinvoke()Фактический вызов внутри методаTransactionAspectSupportКатегорияinvokeWithinTransaction()метод. Поскольку новая версия Spring сильно переписывает эту часть и использует много знаний о реактивном программировании, исходный код здесь не указан.

4) Проблема самовызова Spring AOP

Если нет других в том же классе@TransactionalАннотированный метод вызывается внутри с помощью@TransactionalМетоды аннотации, есть@TransactionalТранзакция аннотированного метода будет признана недействительной.

Это потому чтоSpring AOPПрокси вызывает, потому что только когда@TransactionalУправление транзакциями Spring вступает в силу только тогда, когда аннотированный метод вызывается вне класса.

MyServiceв классеmethod1()перечислитьmethod2()приведет кmethod2()транзакция не удалась.

@Service
public class MyService {

private void method1() {
     method2();
     //......
}
@Transactional
 public void method2() {
     //......
  }
}

Решение состоит в том, чтобы избежать самовызова в том же классе или использовать AspectJ вместо прокси-сервера Spring AOP.

5) @TransactionalКраткое изложение мер предосторожности при использовании

  1. @TransactionalАннотации вступают в силу только тогда, когда они применяются к общедоступным методам, и не рекомендуется использовать их на интерфейсах;
  2. Избегайте вызовов внутри одного класса@TransactionalАннотированный метод, который приведет к сбою транзакции;
  3. правильные настройки@TransactionalRollbackFor и свойства распространения, иначе транзакция может не откатиться.
  4. ......

4. Reference

  1. [Вывод] Параметры @Transactional в управлении транзакциями Spring:www.mobabel.net/spring Управление транзакциями…
  2. Официальная документация Spring:docs.spring.IO/весна/документы…
  3. «Расширенное программирование Spring5»
  4. Тщательно освойте использование @transactional в Spring:Woohoo. IBM.com/developer Я…
  5. Особенности распространения транзакций Spring:GitHub.com/love-SOM сверлит взглядом…
  6. Подробное объяснение поведения распространения транзакций Spring:сегмент fault.com/ah/119000001…
  7. Всесторонний анализ программного управления транзакциями Spring и декларативного управления транзакциями:Woohoo. IBM.com/developer Я…

В этой статье используетсяmdniceнабор текста