Mysql学习记录 - 事务

(建议下面的例子能够自己动手写写,这样理解更加深刻。尤其是事务隔离等级的例子)

当前数据库(Mysql)版本为:8.0.20

mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.20    |
+-----------+
1 row in set (0.00 sec)

下面的例子都是基于t_user表来演示的,表的DDL如下:

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

事务特征

原子性 (atomicity):事务是一个最小的操作单元,强调事务的不可分割

一致性 (consistency):事务的执行的前后数据的完整性保持一致

隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰

持久性(durability) :事务一旦结束,数据就持久到数据库

事务并行出现的问题

(在事务隔离等级中有案例说明)

脏读

        事务A开启,事务B开启,事务B能读到事务A没有提交的数据

不可重复度

        事务A开启,事务B开启,事务B读取到的数据随着事务A的状态变化而发生变化

幻读

         事务A开启,事务B开启,事务B读取到的数据不是真实的数据,即使事务A已经完成

事务隔离级别(下面的流建议动手实现一下印象会深刻很多)

查看系统事务隔离级别:SELECT @@transaction_isolation;

设置系统事务管理级别:SET GLOBAL transaction_isolation = 'READ-COMMITTED';

读未提交(READ-UNCOMMITTED)

在 ‘READ-UNCOMMITTED’ 事务隔离等级下,当事务A开启事务后,执行了insert、delate、update等操作(没有执行commit、rollback操作),事务B任然能读取到事务A的操作结果

演示:

        先打开一个mysql的客户端连到mysql服务器,将数据库隔离等级设置成 'READ-UNCOMMITTED'

C:\Users\lenovo>mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 47
Server version: 8.0.20 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SET GLOBAL transaction_isolation = 'READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

        然后再打开另一个客户端连接到mysql,此时我们的test中的t_user表是一个空表,没有任何数据

1.客户端1开启事务,往t_user表中插入多条数据,没有进行commit操作

2.客户端2开启事务,读取t_user表中的数据,发现能读取到客户端1中插入的数据,即使客户端1没有执行commit操作

3.如果是在实际的开发中,此时客户端1不想往t_user表中插入数据了执行了rollback操作。刚好客户端2在客户端1没有执行rollback之前拿到这些数据去做业务逻辑去了。此时客户端2就读到了脏数据,出现了脏读问题

读已提交(READ-COMMITTED)

在 ‘READ-COMMITTED’ 事务隔离等级下,当事务A开启事务后,执行了insert、delate、update等操作,需要指定commit操作,事务B才能读取到事务A操作的数据结果

演示:

        客户端1连接到mysql服务器,将数据库隔离等级设置成 'READ-COMMITTED',打开客户端2,连接到msyql服务器

1.客户端1开启事务,客户端2也开启事务,客户端1往t_user表中插入几条数据,在客户端1没有执行commit操作的情况下,客户端2是读取不到客户端1的操作结果的。

2.当客户端1执行的commit操作,客户端2此时能读取到客户端1的操作结果。但是此时客户端1从开启事务到现在读取到的数据不一致,我们就说在 'READ-COMMITTED' 模式下解决了脏读问题,但是出现了不可重复读的问题

可重复读(REPEATABLE-READ)

在 ‘REPEATABLE-READ’ 事务隔离等级下,当事务A开启事务后,事务B也开启,尽管事务A执行任何操作(insert、delete、update、rollback、commit),事务B读到的还是上一次提交点读取到的数据

演示:

        客户端1连接到mysql服务器,将数据库隔离等级设置成 'REPEATABLE-READ',打开客户端2,连接到msyql服务器

1.客户端1开启事务,客户端2开启事务。此时客户端2读取t_user表中的数据是空的,客户端1用insert into语句往t_user表中增加了4条数据,在执行commit提交事务。但是客户端读取到的数据依然是空的,只有客户端端2退出当前的事务(这里是commit提交事务),再次读取数据的时候才能读取到客户端1添加的4条数据。在事务隔离等级为 'REPEATABLE-READ' 的模式下,解决了不可重复读的问题,但是带来了一个新的问题:客户端2出现了幻读的问题

序列化(SERIALIZABLE)

在 ‘SERIALIZABLE’ 事务隔离等级下,事务之间处于一个排队的关系,就是事务是挨个执行的

演示:

        客户端1连接到mysql服务器,将数据库隔离等级设置成 'SERIALIZABLE',打开客户端2,连接到msyql服务器

1.客户端1开启事务,客户端2开启事务。客户端1使用insert语句向t_user表增加了4条语句,此时如果客户端2使用select语句查询数据的话你会发现此时处于阻塞状态,只有客户端1的事务完成(使用rollback、commit等等)之后,客户端2才会继续往下执行

2.客户端1执行commt之后,客户端2才会查询到数据

小结一下

  1. 读未提交,存在脏读问题
  2. 读已提交,解决的脏读问题,存在不可重复读问题
  3. 可重复读,解决的不可重复读问题,存在幻读问题
  4. 序列化,解决的脏读、不可重复读、幻读问题
  5. 事务隔离等级越高,性能就越差

おすすめ

転載: blog.csdn.net/qq_27062249/article/details/118656032