MYSQL——事务

什么是事务?

事务是一组SQL 语句或一个独立运行的工作单元并满足ACID 测试。
MYSQL 默认一个SQL 语句为一个事务

事务的ACID 特性

一致性(consistency)

事务将数据库从一种状态转变为下一种一致的状态。在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏。

隔离性(isolation)

脏读、不可重复读、幻读
每个读写事务的对象与其他事务的操作对象相互分离,即该事务提交前对其他事务都不可见,通常使用锁来实现。

原子性(atomic)

原子性是指数据库事务是不可分割的工作单位。只有使实物中所有的数据库操作都执行成功,才算整个事务成功。事务中任何一个SQL语句执行失败,已经执行成功的SQL语句也必须撤销,退回到事务前的状态。

持久性(durability)

事务只要提交了就不能丢失
事务一旦提交,其结果就是永久性的。及时发送宕机等故障,数据库也能将数据恢复。

脏读、幻读、不可重复读

脏读

读到了别的事务回滚前的脏数据。
事务B修改了数据A还没提交,事务C读取了数据A,事务B却回滚了,这样事务C 就读取到了脏数据。

幻读

事务A 通过某些条件的到的数据量不一致。
事务A 首先根据条件索引得到了N条数据,事务B 又增加了满足A 条件索引的M条数据,然后事务A 再次读取的时候发现有N+M条数据,就产生了幻读。

不可重复读

事务两次获取的数据不一致
事务A 读取到一条数据,然后执行逻辑的是时候事务B 将这条数据修改了,事务A再次读取数据的时候读取的是别人修改过的数据。

隔离级别

MYSQL 支持四种隔离级别,分别防止了脏读、幻读、不可重复读。

未提交读 任何情况都不能保证 读读/读写:事务不做任何隔离操、写写:获取记录的排它锁,不能够同时进行,除非一个事务先commit 或rollback
已提交读 可避免脏读发生 oracle默认在这个级别上、读读:事务读的是事务最初的数据快照、读写:读的是数据快照,写的也是数据快照、写写:获取记录的排它锁,不能够同时进行,除非一个事务先commit 或rollback
可重复读 可避免脏读、不可重复读 MYSQL 默认在这个级别上、读读:事务读的都是事务最初的快照、读写:读的是快照数据,写的也是快照数据(除非当前事务提交或者回滚,否则访问的都是快照数据)、写写:获取记录的排它锁,不能够同时进行,除非一个事务先commit 或rollback
串行化 可避免脏读、不可重复读、幻读 MYSQL 默认在这个级别上、读读:事务读的都是事务最初的快照、读写:读的是快照数据,写的也是快照数据(除非当前事务提交或者回滚,否则访问的都是快照数据)、写写:获取记录的排它锁,不能够同时进行,除非一个事务先commit 或rollback

事务处理的相关命令

进行的操作 命令
查看存储引擎 SHOW CREATE TABLE 表名
更改引擎 ALTER TABLE 表名 ENGINE=新引擎名
回滚 ROLLBACK
声明事务开始 BEIGIN
事务提交 COMMIT
查询自动提交功能状态 SELECT @@AUTOCOMMIT
设置自动提交功能 SET AUTOCOMMIT=0或1
设置割离水平 SET SESSION TRANSACTION ISOLATION LEVEL 隔离水平
事务的保存点 save transaction 保存点名字

事务的处理流程

MYSQL 默认一条SQL 语句为一个事务,但是在并发操作下这是不安全的。
转账业务(A 线程转账给B 线程)

① A 线程执行:update bank set count = count - 200 where name = “A”;
② B 线程执行:update bank set count = count +200 where name = “B”;

如果A 线程在执行完后出现了异常,B 线程的SQL 语句执行不到了,那么A 线程的钱少了B 线程的钱没变,就出现了问题。

基于事务的原子性,事务要么全部执行,要么全部不执行。事务的隔离性保证这个事务在处理过程中不被其它事务影响。
在MYSQL 中,用BEGIN来开启一个事务,事务执行完用COMMIT 显式的提交事务就算完成。
在这里插入图片描述
如果在事务运行过程中出现了异常,MYSQL 的事务提供了回滚的功能,可以返回到事务开始之前的状态。
在这里插入图片描述
有时候我们不必回滚到事务的起点,但是由于事务的原子性,我们不得不回滚到起点。
所以MYSQL 提供了事务的保存点,我们可以回滚事务到保存点,也就是在回滚点之前的操作都被归为事务外的事件。
在这里插入图片描述

MYSQL 锁机制

(基于InnoDB 引擎,MyISAM不支持事务,只支持表锁)
InnoDB 支持行锁和表锁,行锁就是给当前行加锁,表锁就是给表加锁。
行锁粒度较小,支持的并发量大,但是容易产生死锁。
表锁粒度较大,支持的额并发量小,不可能产生死锁。
InnoDB默认使用行锁,并且实现了两种标准的行锁:共享锁&排它锁

功能 兼容性 加锁
共享锁 允许获得共享锁的事务读数据 与共享锁兼容,与排它锁不兼容 在串行话隔离级别下默认加共享锁,在其他隔离级别下在select语句后加lock in share mode 显式的加锁
排它锁 允许获得共享锁的事务更新或者删除数据 与共享锁不兼容,与排它锁不兼容 在默认的可重复读的隔离级别下,InnoDB 会自动的为增删改操作加排它锁,也可以在select 语句后加for undate 显式的加排它锁

当前读&快照读

当前读
即加锁读,读取记录的最新版本,会加锁保证其他并发事务不能修改当前记录,直至获取锁的事务释放锁;
使用当前读的操作主要包括:显式加锁的读操作与插入/更新/删除等写操作,如下所示:

select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

当Update SQL被发给MySQL后,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁,待MySQL Server收到这条加锁的记录之后,会再发起一个Update请求,更新这条记录。一条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止。因此,Update操作内部,就包含了当前读。同理,Delete操作也一样。Insert操作会稍微有些不同,简单来说,就是Insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。
快照读
即不加锁读,读取记录的快照版本而非最新版本,通过MVCC实现;
InnoDB默认的RR事务隔离级别下,不显式加『lock in share mode』与『for update』的『select』操作都属于快照读,保证事务执行过程中只有第一次读之前提交的修改和自己的修改可见,其他的均不可见;

MVCC

MVCC的最大好处:读不加任何锁,读写不冲突,对于读操作多于写操作的应用,极大的增加了系统的并发性能;
在这里插入图片描述

锁算法

InnoDB 支持者三种锁算法
在这里插入图片描述
InnoDB所有的行锁算法都是基于索引实现的,锁定的也都是索引或索引区间;
不同的事务隔离级别、不同的索引类型、是否为等值查询,使用的行锁算法也会有所不同;下面仅以InnoDB默认的RR隔离级别、等值查询为例,介绍几种行锁算法:
在这里插入图片描述
1.等值查询使用聚簇索引
在这里插入图片描述
2.等值查询使用唯一索引
在这里插入图片描述
3.等值查询使用辅助索引
在这里插入图片描述

参考资料

https://segmentfault.com/a/1190000014133576

猜你喜欢

转载自blog.csdn.net/Alyson_jm/article/details/83714948