MySQL中的事务、4大特性、隔离级别是什么

63次阅读
没有评论

共计 7865 个字符,预计需要花费 20 分钟才能阅读完成。

本篇内容主要讲解“MySQL 中的事务、4 大特性、隔离级别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“MySQL 中的事务、4 大特性、隔离级别是什么”吧!

本文操作和测试所用的环境版本是 5.7.21

mysql  select version();
+-----------+
| version() |
+-----------+
| 5.7.21 |
+-----------+
1 row in set (0.00 sec)

记住:我们常见的 MySQL 存储引擎中只有 InnoDB 是支持事务的。所以下面的操作也都是在 InnoDB 下做的。

一. 什么是事务

事务就是现实中抽象出来一种逻辑操作,要么都执行,要么都不执行,不能存在部分执行的情况。

比较经典的案例就是银行转账:小 A 向小 B 转账 100 元

正常的情况:小 A 的账户扣减 100 元,小 B 的账户增加 100 元。

非正常情况: 小 A 的账户扣减 100 元,小 B 账户金额不变。

非正常情况下,小 A 账户扣减 100 之后银行系统出现问题,小 B 账户增加 100 元的操作并没有执行。也就是两边金额对不上了,小 A 不愿意,小 B 不愿意,银行也不愿意啊。事务的出现就是为了避免非正常情况的出现,让大家都满意。

二. 事务的 4 大特性(ACID)

1. 原子性(Atomicity)

事务的操作是不可分割的,要么都操作,要么都不操作,就像转账一样,不存在中间状态。而且这个原子性不是说只有一个动作,可能会有很多的操作,但是从结果上看是不可分割的,也就是说原子性是一个结果状态。

2. 一致性(Consistency)

执行事务的前后,数据保持一致,就像银行账户系统一样无论事务是否成功,两者的账户总额应该是一样的。

3. 隔离性(Isolation)

多个事务同时操作数据的时候,多个事务直接互相隔离,不会互相影响。

4. 持久性(Durability)

一个事务在提交后对数据的影响是永久的,写入磁盘中不会丢失。

三. 显式事务、隐式事务

mysql 的事务分为显式事务和隐式事务, 默认的事务是隐式事务,由变量 autocommit 在操作的时候会自动开启,提交,回滚。

控制的关键命令如下

set autocommit=0; --  关闭自动提交事务(显式)set autocommit=1; --  开启自动提交事务(隐式) --  当 autocommit= 0 的时候手动控制事务
rollback; --  回滚事务
commit; --  提交事务
--  当 autocommit=1  自动提交事务,但是可以控制手动提交
start transaction; --  开启事务(或者用 begin 开启事务)commit; --  提交事务
rollback; --  回滚事务
SAVEPOINT  保存点名称; --  保存点 (相当于存档,可以不用回滚全部操作)
rollback to  保存点; --  回滚到某个保存点  (这个后面就不测试,知道有这个操作就行)

先建一张表 ajisun

mysql  create table ajisun(id int(5), name varchar(20) character set utf8 COLLATE utf8_bin ) engine=innodb character set= utf8mb4 COLLATE = utf8mb4_bin;
Query OK, 0 rows affected (0.03 sec)

1. 隐式事务

--  看下当前 autocommit 的状态是,默认是 on 状态
mysql  show variables like  autocommit  
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.01 sec)
--  插入一条数据
mysql  insert into ajisun values(1, 阿纪 
Query OK, 1 row affected (0.00 sec)
mysql  rollback;
--  执行 rollback  也是没有效果的,还是能够查询到插入的数据(不需要我们手动控制 commit)mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 |  阿纪  |
+------+--------+
1 row in set (0.00 sec)

2. 显式事务方式 1

显式事务由我们自己控制事务的开启,提交,回滚等操作

--  开启显式事务 - 回滚
mysql  set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 |  阿纪  |
+------+--------+
1 row in set (0.00 sec)
mysql  insert into ajisun values(2, 纪先生 
Query OK, 1 row affected (0.00 sec)
--  插入后可以看见 2 条数据
mysql  select * from ajisun;
+------+-----------+
| id | name |
+------+-----------+
| 1 |  阿纪  |
| 2 |  纪先生  |
+------+-----------+
2 rows in set (0.00 sec)
--  回滚之后上面插入的数据就没了
mysql  rollback;
Query OK, 0 rows affected (0.00 sec)
mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 |  阿纪  |
+------+--------+
1 row in set (0.00 sec)
--  插入一条数据
mysql  insert into ajisun values(2, ajisun 
Query OK, 1 row affected (0.01 sec)
--  提交
mysql  commit;
Query OK, 0 rows affected (0.00 sec)
--  回滚
mysql  rollback;
Query OK, 0 rows affected (0.00 sec)
--  先提交 commit,在 rollback  数据依然存在,说明 commit 生效,事务已提交,回滚就不生效了。mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 1 |  阿纪  |
| 2 | ajisun |
+------+--------+
2 rows in set (0.00 sec)

3. 显式事务方式 2

使用 start transaction

先改成默认的事务 set autocommit=1;

--  开启事务
mysql  start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql  delete from ajisun where id=1;
Query OK, 1 row affected (0.00 sec)
--  提交事务
mysql  commit;
Query OK, 0 rows affected (0.01 sec)
mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 2 | ajisun |
+------+--------+
1 row in set (0.00 sec)
--  开启事务
mysql  start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql  delete from ajisun where id =2;
Query OK, 1 row affected (0.01 sec)
--  回滚事务
mysql  rollback;
Query OK, 0 rows affected (0.01 sec)
--  删除操作失效了
mysql  select * from ajisun;
+------+--------+
| id | name |
+------+--------+
| 2 | ajisun |
+------+--------+
1 row in set (0.00 sec)

四. 并发事务中的问题

如果对表的操作同一时间只有一个事务就不会有问题,但是这是不可能的。现实中都是尽可能的利用,多个事务同时操作。多个事务就会带来不少的问题,例如脏读,脏写,` 不可重复读,幻读

1. 脏读

一个事务读取到另一个未提交事务修改后的数据 这就是脏读。

例如两个事务 a,b: 同时操作一条记录

a 事务修改记录后还没有正式提交到数据库,这时 b 事务去读取,然后用读取到的数据进行后续操作。

如果 a 事务回滚了,这个修改后的数据就不存在了,那么 b 事务就是在使用一个不存在的数据。这种就是脏数据。

2. 脏写(数据丢失)

一个事务修改了另一个未提交事务修改过的数据

例如两个事务 a,b: 同时操作一条记录

a 事务修改后没有提交, 接着 b 事务也修改同一条数据,然后 b 事务提交数据。

如果 a 事务回滚自己的修改,同时也把 b 事务的修改也回滚了,造成的问题就是:b 事务修改了 也提交了,但是数据库并没有改变,这种情况就是脏写。

3. 不可重复读

一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。

也就是在同一个事务中多次读取同一条记录,得到的内容都不一样(在每次读取之前都有其他事务完成修改并提交),这就是不可重复读。

4. 幻读

在一个事务内 相同条件查询数据,先后查询到的记录数不一样

也就是一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读

不可重复读和幻读的区别:不可重复读重点在于同一条记录前后数据值不一样(内容的变化),而幻读重点在于相同查询条件前后所获取的记录数不一样(条数的变化)

五. 事务的隔离级别

上面说的事务的并发问题,在不同的场景下要求不一样,能接受的问题也不一样。他们之间的严重性排序如下:

脏写 脏读 不可重复读 幻读

MySQL 中提供了 4 种隔离级别来处理这几个问题,如下

隔离级别脏读不可重复读幻影读 READ- UNCOMMITTED√√√READ-COMMITTED×√√REPEATABLE-READ××√SERIALIZABLE×××

SQL 标准定义了四个隔离级别:

READ-UNCOMMITTED(读未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读。但是并发度最高

READ-COMMITTED(读已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读仍有可能发生。

REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,该级别可以防止脏读、不可重复读以及幻读。并发度也是最低的

MySQL 默认采用的  REPEATABLE_READ  隔离级别  
Oracle 默认采用的  READ_COMMITTED  隔离级别 

1. 如何设置隔离级别

可以通过变量参数 transaction_isolation 查看隔离级别

mysql  SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
mysql  show variables like  %transaction_isolation% 
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)

修改的命令:SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL $[level];

level 的值就是 4 中隔离级别 READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE

设置全局隔离级别

只对执行完该语句之后产生的会话起作用。

当前已经存在的会话无效。

set global transaction_isolation= read-uncommitted 
set global transaction_isolation= read-committed 
set global transaction_isolation= repeatable-read 
set global transaction_isolation= serializable

例如:

会话 A

mysql  set global transaction_isolation= serializable 
Query OK, 0 rows affected (0.01 sec)
mysql  select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE |
+--------------------------------+
1 row in set (0.00 sec)
--  当前会话(设置之前就已经存在的会,级别是默认的)mysql  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)

会话 B(set 之后新建的会话)

mysql  select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE |
+--------------------------------+
1 row in set (0.00 sec)
mysql  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE |
+-------------------------+
1 row in set (0.00 sec)

设置会话的隔离级别

对当前会话的所有后续的事务有效

该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务。

如果在事务之间执行,则对后续的事务有效。

set session transaction_isolation= read-uncommitted 
set session transaction_isolation= read-committed 
set session transaction_isolation= repeatable-read 
set session transaction_isolation= serializable

比如:

会话 A

mysql  set session transaction_isolation= read-uncommitted 
Query OK, 0 rows affected (0.00 sec)
mysql  select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)

新建会话 B(依然是默认的级别:可重复读)

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

2. 怎么选择隔离级别

一般情况下默认的可重复读就好了,一般很少改这个,除非业务场景特殊

记住一点:隔离级别越高,并发问题就越少,但并发性也就越低,所以还是要根据业务选择来。

六. 总结

事务的四大特性:原子性,一致性,隔离性,持久性

事务的常见命令:

set autocommit=0/1; --  关闭 / 开启自动提交事务
start transaction; --  开启事务(或者用 begin)rollback; --  回滚事务
commit; --  提交事务 

并发事务的问题:脏写 脏读 不可重复读 幻读

需要熟悉事务的 4 种隔离级别以及 MySQL 默认级别

怎么设置隔离级别(global,session)

到此,相信大家对“MySQL 中的事务、4 大特性、隔离级别是什么”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计7865字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)