mysql事务四个安全级别_四个MySQL事务隔离级别的详细说明

73a4044d0f0f824d953fd9a1aa3d63ab.png

本文中的实验测试环境: Windows 10 + cmd + MySQL5.6.36 + InnoDB

首先,交易的基本要素(ACID)

1. 原子性: 事务开始后

2. 一致性(Consistency): 在事务之前和之后,的完整性约束没有被破坏. 例如,如果A汇款到B,则A不可能扣款,但B尚未收到.

3. 隔离: 同时隔离级别 详解,只允许一个事务请求相同的数据,并且不同的事务不会相互干扰. 例如,A正在从银行卡提款. 在A的提款过程结束之前,B无法将钱转入该卡.

4. 耐用性: 交易完成后,交易对所做的所有更新将保存到中,并且无法回滚.

摘要: 原子性是事务隔离的基础,隔离和持久性是手段,最终目的是保持数据一致性.

第二,交易并发问题

1. 脏读: 事务A读取由事务B更新的数据,然后B回滚操作,然后A读取的数据是脏数据

2. 不可重复读取: 事务A多次读取同一数据,而事务B在多次读取过程中更新并提交数据,导致事务A多次读取同一数据. 结果不一致.

3. 妙读: 系统管理员A将中所有学生的成绩从特定分数更改为ABCDE分数,但是系统管理员B此时插入了特定分数的记录. 当系统管理员A更改后结束后,我发现还有另一条记录未更改,就好像发生了幻觉一样. 这称为幻影阅读.

摘要: 不可重复读取和幻像读取很容易混淆. 不可重复读注重修改,而幻像读注重添加或删除. 要解决不可重复读取的问题,您只需要锁定满足条件的行,而对于不可思议的读取,则需要锁定表

efeaa6557b0ba2d328afbfc0a801397b.png

b2dbef34b630e313335ea324269d43f7.png

三,MySQL事务隔离级别

mysql的默认事务隔离级别是repeatable-read

8f541720fdbe94e3dfbb8a7427728c39.png

四,使用示例来说明每个隔离级别的情况

1. 未提交阅读:

(1)打开客户端A,并将当前事务模式设置为读取未提交(读取未提交),查询表帐户的初始值:

81081aa0b553091b8f280c34d042871a.png

(2)在提交客户A的交易之前,请打开另一个客户B并更新表格帐户:

32e0f033ef87fc1793bd6975a7ff4f5f.png

(3)目前,尽管客户B的交易尚未提交,但客户A可以查询B的更新数据:

3250eb5099d94099037edd5b30ca2bd7.png

(4)一旦由于某种原因回滚了客户B的交易,所有操作都将被撤消,那么客户A查询的数据实际上就是脏数据:

62d352871c8801cc710466d1cbe7299f.png

14626eefa6a3430a38e20021451f24a9.png

(5)在客户端A上执行更新语句update account set balance = balance-50,其中id = 1,lilei的余额没有变为350,但实际上为400. 一致性并不奇怪. 不问数据?如果您这样认为,那是天真的. 在该应用程序中,我们将使用400-50 = 350,并且不知道其他会话已回滚. 要解决此问题,您可以使用提交的提交的隔离级别

25aa22185720b3471ca84c93de8c3bf1.png

2. 阅读已提交

(1)打开客户端A,并将当前事务模式设置为读取已提交(未提交读取),即查询表帐户的初始值:

8776d0e1b3ef517d280dbf6ad510cb25.png

(2)在提交客户A的交易之前,请打开另一个客户B并更新表格帐户:

e6fa8280c52b0a2053029ab383a103ac.png

(3)此时,客户端B的事务尚未提交,客户端A无法查询B的更新数据,从而解决了读取不干净的问题:

8bbe8353ba1f0b16eb9ce41d5e2cf7fa.png

(4)客户B的交易提交

f6275df82e35ddc21931e9dd8542a1d7.png

(5)客户端A执行与上一步相同的查询,结果与上一步不一致,即存在不可重复读取的问题. 在应用程序中,假设我们在客户端A的会话中并查询lilei的余额为450,但是其他事务将lilei的余额值更改为400. 我们不知道如果您使用450进行其他操作,问题,但概率确实很小. 如果要避免此问题,可以使用可重复的隔离级别

6393574c41f55b0bf31baef79d1af611.png

fa40a86eed5e712b8c6a20b7a46c7b02.png

3. 重复阅读

(1)打开一个客户端A,并将当前事务模式设置为可重复读取,查询表帐户的初始值:

3c3a5062d64344f8431c6143fb1804eb.png

(2)在提交客户A的交易之前,请打开另一个客户B,更新表格帐户并提交. 客户B的交易实际上可以修改客户A的交易查询的行,即mysql. 重复读取不会锁定事务查询的行. 这超出了我的预期. 当sql标准中的事务隔离级别是可重复读取时,读取和写入操作必须锁定该行. MySQL实际上没有锁,所以我去了. 注意锁定应用程序中的行,否则您将使用步骤(1)中lilei的余额作为中间值400进行其他操作

2e6806300c0d3e93463d0d909e976b8b.png

(3)在客户端A上执行步骤(1)的查询:

df126bb84f5474eca964280607a8950a.png

(4)执行步骤(1),lilei的余额仍为400,步骤(1)的查询结果一致,没有不可重复读取的问题;然后执行更新余额= balance-50,其中id = 1,余额不等于400-50 = 350,在步骤(2)中通过350计算lilei的余额值,因此为300,数据的一致性为没有销毁,这有点神奇,也许这是mysql <

的特征

mysql> select * from account;

+------+--------+---------+

| id | name | balance |

+------+--------+---------+

| 1 | lilei | 400 |

| 2 | hanmei | 16000 |

| 3 | lucy | 2400 |

+------+--------+---------+

rows in set (0.00 sec)

mysql> update account set balance = balance - 50 where id = 1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from account;

+------+--------+---------+

| id | name | balance |

+------+--------+---------+

| 1 | lilei | 300 |

| 2 | hanmei | 16000 |

| 3 | lucy | 2400 |

+------+--------+---------+

rows in set (0.00 sec)

(5)在客户端A上开始交易,并查询表帐户的初始值

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;

+------+--------+---------+

| id | name | balance |

+------+--------+---------+

| 1 | lilei | 300 |

| 2 | hanmei | 16000 |

| 3 | lucy | 2400 |

+------+--------+---------+

rows in set (0.00 sec)

(6)在客户端B上开始交易,添加新数据,余额字段值为600,然后提交

v2-e4176a65c165e29494112f281c6edf3f_b.jpg

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values(4,'lily',600);

Query OK, 1 row affected (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.01 sec)

(7)计算客户A的余额之和,值为300 + 16000 + 2400 = 18700,不包括客户B的值,然后计算客户A提交后的余额之和,即为19300 ,这是因为包含了客户端B的600. 从客户的角度看,客户看不到客户B. 这会感觉到这个派是世界之外的,还有600多块. 这是幻影阅读. 从开发人员的角度来看,数据的一致性并未受到破坏. 但是在应用程序中,我们的代码可能会向用户提交18700. 如果必须以小概率避免这种情况,则必须采用下面描述的事务隔离级别“序列化”

mysql> select sum(balance) from account;

+--------------+

| sum(balance) |

+--------------+

| 18700 |

+--------------+

1 row in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

mysql> select sum(balance) from account;

+--------------+

| sum(balance) |

+--------------+

| 19300 |

+--------------+

1 row in set (0.00 sec)

4. 序列化

(1)打开一个客户端A,并将当前事务模式设置为可序列化,查询表帐户的初始值:

mysql> set session transaction isolation level serializable;

Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;

+------+--------+---------+

| id | name | balance |

+------+--------+---------+

| 1 | lilei | 10000 |

| 2 | hanmei | 10000 |

| 3 | lucy | 10000 |

| 4 | lily | 10000 |

+------+--------+---------+

rows in set (0.00 sec)

(2)打开客户端B并将当前事务模式设置为可序列化. 插入一条记录并报告错误. 该表已锁定. 插入失败. 当mysql中的事务隔离级别可序列化时,该表将被锁定. 在这种情况下,此隔离级别的并发性非常低. 通常,一个事务占用一张桌子. 其他数万笔交易只能在等待他完成提交后才能使用. 它很少在开发中使用.

mysql> set session transaction isolation level serializable;

Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values(5,'tom',0);

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

补充:

1. SQL规范规定的标准,不同的具体实现可能有所不同

2. mysql中的默认事务隔离级别是可重复读取,并且不锁定读取行

3. 当事务隔离级别被序列化时,读取数据将锁定整个表

4. 阅读本文时,如果您站在开发人员的角度,您可能会感觉到没有可重复的阅读和幻像阅读. 没有逻辑问题. 最终数据仍然是一致的,但是从用户的角度来看. 他们通常只看到一个事务(仅看到客户端A,不知道客户端B的秘密存在),并且不考虑事务并发执行的现象. 一旦相同的数据出现多次,结果有所不同,或者新记录突然出现,他们可能会怀疑,这是用户体验的问题.

5. 当事务在mysql中执行时,最终结果将不会出现数据一致性问题,因为在事务中,mysql执行某个操作可能不会使用前一个操作的中间结果,这将基于其他实际情况处理并发事务,这似乎是不合逻辑的,但是它保证了数据的一致性;但是当在应用程序中执行交易时,下一个操作将使用一个操作的结果,并且将执行其他计算. 这是我们必须要小心的事情. 重复读取时应锁定行,序列化期间必须锁定表,否则数据一致性将被破坏.

6. 当事务在mysql中执行时,mysql会根据每个事务的实际情况进行全面处理,导致数据的一致性并没有被破坏,而是应用程序按照逻辑例程来打牌,而mysql没有聪明,这是不可避免的. 存在数据一致性问题.

7. 隔离级别越高,就可以保证越多的数据完整性和一致性,但是对并发性能的影响越大,鱼爪和熊掌不能兼得. 对于大多数应用程序,您可以优先将系统的隔离级别设置为“ Read Committed”,这可以避免脏读并具有良好的并发性能. 尽管它将引起并发问题,例如不可重复的读取和幻像读取,但是在个别情况下,可能会出现此类问题,但应用程序可以由悲观锁或乐观锁来控制.

以上是本文的全部内容,希望对大家的学习有所帮助,并希望您支持脚本编写室.

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-190492-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值