本篇内容是关于SQL事物知识,主要包括事物的概念,ACID,幻读,不可重复度,脏度等内容;mysql
学习本篇的基础是知识追寻者发过的SQL系列文章(公众号读者直接在专栏里面找便可)sql
本套教程数据库
公众号:知识追寻者json
知识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)服务器
事物意指一组原子性的的SQL操做,即保证一组 SQL 语句要么所有执行,要么所有不执行;markdown
一个经典的案例银行转帐: 小知转帐100元给小识,操做步骤以下架构
假设 有张金额表 money,对应SQL语句以下并发
如上语句就是 一次原子性操做,begin
为开启事物, commit
为提交事物;假设没有begin 和 commit ,在执行语句3的时候发生了断电,小知的帐号金额扣除了100,但小识的金额却没有加上100,这就形成了数据的不一致,故事物在SQL中占有主导性地位,特别是关于金额类操做;学习事物必须知足4个条件(ACID), 原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。ide
原子性的概念比较简单,就是事物被当初一个最小的单位,其不可分割,而且整个事物中的操做要么所有失败,要么所有成功;oop
一致性 的意思就是 数据从一种状态转移至另外一种状态,其数据完整没有被破坏;如上例子小知扣除100元后,小识帐号金额没有增长100,这就是状态转移后破坏了数据的一致性;
隔离性是指,一个事物在作出修改后至到事物提交前,其它的事物是不可见的;如上例子小知帐号有500元 扣除100元后, 假设有另一个事物参与进来,其是不能看见小知帐号为400元,应该是500元;
持久性的概念更加简单,即一旦事物提交,则数据修改操做永久保存到数据库中;若是服务器发生故障则不会对持久化的数据产生任何影响;
mysql 中 经常使用 的就是 begin commit rollback 三个语句;
事物的隔离级别在每种数据库的存储引擎中都不同,通常是提交读,但mysql使用InnoDB 时 是可重复度;
读未提交
(read uncommited) 即事物修改后语句后并无提交,其修改的内容对其它事物是可见的,此时就会出现脏读,如上例子 小知帐号500扣除 100 元 ,被其它事物读看见读取了400元,就出现了脏度;因此读未提交在实际生产环境中基本不会使用到读已提交
(read commited) 即一个事物只能读取到另外一个事物已经提交后的数据;如上例子假设小知帐号金额500元, 小知帐号金额扣除100,小识帐号金额 加100,事物提交后,另外一个事物读取小知帐号金额400;可重复读
(repeatable read)即同一个事物屡次读取的数据先后一致;如上例子,小知帐号500元,当执行如上操做事物完成后,另外一个事物读取n次小知的帐号都是400元;可串行化
(serializable)即在每行的数据上都加上一行读锁,会致使锁竞争问题,数据库性能会下降;事物的最高级别;实际生产环境中也不多用到;mysql 中可使用 set transction 来设置 事物的隔离级别 即(read-uncommitted、read-committed、repeatable-read 和 serializable)
-- mysql 5版本
select @@tx_isolation;
set tx_isolation = 'read-uncommitted';
-- mysql 8版本
select @@transaction_isolation;
set transaction_isolation = '';
复制代码
脏读
:事务A读取了事务B更新的数据,而后B回滚操做,那么A读取到的数据是脏数据不可重复读
:事务 A 屡次读取同一数据,事务 B 在事务A屡次读取的过程当中,对数据做了更新并提交,致使事务A屡次读取同一数据时,结果 不一致。幻读
:A将数据库中的数据进行修改,可是B就在这个时候插入了一条数据,当A改完后发现还有一条记录没有改过来,这就叫幻读。因此幻读针对插入语句;mysql 的 InnoDB 经过 多版本并发控制 (MVCC) 解决了幻读问题;
一张顾客表,建表语句以下
CREATE TABLE `customer` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`customer_name` varchar(255) DEFAULT NULL COMMENT '顾客名称',
`gender` varchar(255) DEFAULT NULL COMMENT '性别',
`telephone` varchar(255) DEFAULT NULL COMMENT '电话号码',
`register_time` timestamp NULL DEFAULT NULL COMMENT '注册时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='顾客表';
复制代码
提交事物示例
begin;
INSERT INTO `zszxz`.`customer`(`customer_name`, `gender`, `telephone`, `register_time`) VALUES ('知识追寻者', '男', '9991', NULL);
commit;
复制代码
此时 数据库中会增长一条数据;
回滚示例
begin;
INSERT INTO `zszxz`.`customer`(`customer_name`, `gender`, `telephone`, `register_time`) VALUES ('知识追寻者', '男', '9991', NULL);
rollback;
复制代码
此时数据中并无添加新数据
实际上Mysql 中每次的事物操做默认都是自动提交(AUTOCOMMIT) , 即每条语句操做都会自动提交;
读者可使用 以下 语句查看 mysql 的 AUTOCOMMIT 是否 开启
SHOW VARIABLES LIKE 'AUTOCOMMIT'
复制代码
操做示例以下:
使用以下语句能够对 自动提交进行设置
关注知识追寻者: