"Эта статья была включена в проект 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 юаней Сяохуну, этот перевод будет включать две ключевые операции:
-
Уменьшите баланс Сяо Мина на 1000 юаней.
-
Увеличьте баланс Сяохун на 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)
метод для получения транзакции, параметры в этом методеTransactionDefinition
class , который определяет некоторые основные атрибуты транзакции.
Так что жеСвойства транзакцииШерстяная ткань?
Атрибуты транзакций можно понимать как некоторые базовые конфигурации транзакций, описывающие, как политики транзакций применяются к методам.
Атрибуты транзакции включают 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
Использование аннотации по умолчанию — это поведение распространения транзакции. Если транзакция уже существует, присоединиться к ней, если текущей транзакции нет, создать новую транзакцию. Это:
- Если внешний метод не запускает транзакцию,
Propagation.REQUIRED
Декорированный внутренний метод заново откроет свою собственную транзакцию, а открытые транзакции не зависят друг от друга и не мешают друг другу. - Если внешний метод запускает транзакцию и
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
. Это:
- В случае, когда внешний метод не открывает транзакцию
Propagation.NESTED
иPropagation.REQUIRED
Эффект тот же, измененные внутренние методы будут заново открывать свои собственные транзакции, а открытые транзакции независимы друг от друга и не мешают друг другу. - Если внешний метод запускает транзакцию,
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
(перечитываемый)Ни о какой потере производительности речи не идет.
Дополнительные сведения об уровнях изоляции транзакций см.
- «Одна статья поможет вам легко понять уровень изоляции транзакций (подробная графика и текст)»
- Интервьюер: Вы сказали, что знакомы с транзакциями 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
Будет открыта отдельная транзакция, и если данные будут изменены другими транзакциями в середине, последнее значение будет прочитано в режиме реального времени.
Поделитесь ответами других людей об атрибутах транзакции только для чтения:
- Если вы выполняете один оператор запроса за раз, нет необходимости включать поддержку транзакций, база данных поддерживает согласованность чтения во время выполнения SQL по умолчанию;
- Если вы выполняете несколько операторов запроса одновременно, например, статистический запрос, запрос отчета, в этом сценарии множественный SQL-запрос должен обеспечивать общую согласованность чтения, в противном случае после предыдущего SQL-запроса и до следующего SQL-запроса данные будут другие пользователи изменятся, общий статистический запрос будет иметь противоречивые данные чтения. В это время должна быть включена поддержка транзакций.
3.3.4 Правила отката транзакции
Эти правила определяют, какие исключения вызовут откат транзакции, а какие нет. По умолчанию транзакция откатывается только при возникновении исключения времени выполнения (подкласса RuntimeException).Ошибка также вызывает откат транзакции, но не откат при обнаружении проверенного исключения.
Если вы хотите откатить определенный тип исключения, который вы определили, вы можете сделать это:
@Transactional(rollbackFor= MyException.class)
3.4 Подробное объяснение использования аннотации @Transactional
1) @Transactional
сфера действия
- метод: Рекомендуется использовать аннотации к методам, но следует отметить, что:Эту аннотацию можно применять только к общедоступным методам, иначе она не вступит в силу.
- своего рода: если эта аннотация используется в классе, это означает, что аннотация действительна для всех общедоступных методов в классе.
- интерфейс: Не рекомендуется использовать на интерфейсах.
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
Краткое изложение мер предосторожности при использовании
-
@Transactional
Аннотации вступают в силу только тогда, когда они применяются к общедоступным методам, и не рекомендуется использовать их на интерфейсах; - Избегайте вызовов внутри одного класса
@Transactional
Аннотированный метод, который приведет к сбою транзакции; - правильные настройки
@Transactional
RollbackFor и свойства распространения, иначе транзакция может не откатиться. - ......
4. Reference
- [Вывод] Параметры @Transactional в управлении транзакциями Spring:www.mobabel.net/spring Управление транзакциями…
- Официальная документация Spring:docs.spring.IO/весна/документы…
- «Расширенное программирование Spring5»
- Тщательно освойте использование @transactional в Spring:Woohoo. IBM.com/developer Я…
- Особенности распространения транзакций Spring:GitHub.com/love-SOM сверлит взглядом…
- Подробное объяснение поведения распространения транзакций Spring:сегмент fault.com/ah/119000001…
- Всесторонний анализ программного управления транзакциями Spring и декларативного управления транзакциями:Woohoo. IBM.com/developer Я…
В этой статье используетсяmdniceнабор текста