1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-25 02:27:10 +08:00

Update spring-transaction.md

This commit is contained in:
shuang.kou 2020-04-27 17:59:51 +08:00
parent 21e2789fbf
commit da239bd8de

View File

@ -1,9 +1,13 @@
## 什么是事务?
**事务是逻辑上的一组操作,要么都执行,要么都不执行。**
**事务是逻辑上的一组操作,要么都执行,要么都不执行。**
*Guide哥大家应该都能背上面这句话了下面我结合我们日常的真实开发来谈一谈*
具体对应到我们日常开发过程中是这样的:**我们系统的每个业务方法可能包括了多个原子性的数据库操作,并且原子性的数据库操作是有依赖的,它们要不都执行,要不就都不执行。**
另外,需要格外注意的是:**事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的`innodb`引擎。但是如果把数据库引擎变为myisam那么程序也就不再支持事务了**
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元这个转账会涉及到两个关键操作就是将小明的余额减少1000元将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃导致小明余额减少而小红的余额没有增加这样就不对了。事务就是保证这两个关键操作要么都成功要么都要失败。
```java
@ -33,10 +37,10 @@ public class OrdersService {
- **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- **一致性:** 执行事务前后,数据保持一致;
- **隔离性:** 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的
- **隔离性:** 并发访问数据库时,一个用户的事物不被其他事务所干扰也就是说多个事务并发执行时,一个事务的执行不应影响其他事务的执行
- **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
## Spring对事务的支持
## 详谈Spring对事务的支持
### Spring支持两种方式的事务管理
@ -146,7 +150,7 @@ public interface TransactionStatus{
举个例子!
我们在 A 类的`aMethod`方法中调用了 B 类的 `bMethod()` 方法。这个时候就涉及到业务层方法之间互相调用的事务问题。**我们的 `bMethod() `如果发生异常需要回滚,怎么样才能让 `aMethod()`也跟着回滚呢?**
我们在 A 类的`aMethod`方法中调用了 B 类的 `bMethod()` 方法。这个时候就涉及到业务层方法之间互相调用的事务问题。我们的 `bMethod() `如果发生异常需要回滚,如何配置事务传播行为才能让 `aMethod()`也跟着回滚呢?
```java
Class A {
@ -219,7 +223,7 @@ public enum Propagation {
```
**正确的事务传播类型的可能值如下**
**正确的事务传播行为可能的值如下**
**1.`TransactionDefinition.PROPAGATION_REQUIRED`**
@ -306,14 +310,12 @@ Class B {
}
```
**5.`TransactionDefinition.PROPAGATION_MANDATORY`**
如果当前存在事务则加入该事务如果当前没有事务则抛出异常。mandatory强制性
这个使用的很少,就不举例子来说了。
**若是错误的配置以下三种事务传播行为,事务将不会发生回滚,这里不对照案例讲解了,使用的很少。**
- **`TransactionDefinition.PROPAGATION_SUPPORTS`**: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
@ -326,7 +328,34 @@ Class B {
#### 事务只读属性
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
```java
package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface TransactionDefinition {
......
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();
}
```
对于只有读取数据查询的事务可以指定事务类型为readonly即只读事务。只读事务不涉及数据的修改数据库会提供一些优化手段适合用在有多条数据库查询操作的方法中。
很多人就会疑问了,为什么我一个数据查询操作还要启用事务支持呢?
拿 MySQL 的 innodb 举例子,根据官网 [https://dev.mysql.com/doc/refman/5.7/en/innodb-autocommit-commit-rollback.html](https://dev.mysql.com/doc/refman/5.7/en/innodb-autocommit-commit-rollback.html) 描述:
> MySQL默认对每一个新建立的连接都启用了`autocommit`模式。在该模式下每一个发送到MySQL服务器的`sql`语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务,并开启一个新的事务。
但是,如果你给方法加上了`Transactional`注解的话,这个方法执行的所有`sql`会被放在一个事务中。如果声明了只读事务的话,数据库就会去优化它的执行,并不会带来其他的什么收益。只读事务并不能避免幻读。如果不加`Transactional`,每条`sql`会开启一个单独的事务,中间被其它事务改了数据,都会实时读取到最新值。
分享一下关于事务只读属性,其他人的解答:
1. 如果你一次执行单条查询语句则没有必要启用事务支持数据库默认支持SQL执行期间的读一致性
2. 如果你一次执行多条查询语句例如统计查询报表查询在这种场景下多条查询SQL必须保证整体的读一致性否则在前条SQL查询之后后条SQL查询之前数据被其他用户改变则该次整体的统计查询将会出现读数据不一致的状态此时应该启用事务支持
#### 事务回滚规则
@ -336,10 +365,6 @@ Class B {
@Transactional注解就代表支持事务管理@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。如果这个注解在类上那么表示该注解对于所有该类中的public方法都生效如果注解出现在方法上则代表该注解仅对该方法有效会覆盖先前从类层次继承下来的注解。
## Reference
1. 可能是最漂亮的Spring事务管理详解:https://juejin.im/post/5b00c52ef265da0b95276091