本篇内容是关于SQL事物知识,主要包括事物的概念,ACID,幻读,不可重复度,脏度等内容;
学习本篇的基础是知识追寻者发过的SQL系列文章(公众号读者直接在专栏里面找即可)
《SQL-你真的了解什么SQL么?》
《SQL-小白最佳入门sql查询一》
《SQL-小白最佳入门sql查询二》
《SQL- 多年开发人员都不懂的插入与更新删除操作注意点》
公众号:知识追寻者
知识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)
事物意指一组原子性的的SQL操作,即保证一组 SQL 语句要么全部执行,要么全部不执行;
一个经典的案例银行转账: 小知转账100元给小识,操作步骤如下
假设 有张金额表 money,对应SQL语句如下
如上语句就是 一次原子性操作,begin
为开启事物, commit
为提交事物;假设没有begin 和 commit ,在执行语句3的时候发生了断电,小知的账号金额扣除了100,但小识的金额却没有加上100,这就造成了数据的不一致,故事物在SQL中占有主导性地位,特别是关于金额类操作;学习事物必须满足4个条件(ACID), 原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
原子性的概念比较简单,就是事物被当初一个最小的单位,其不可分割,并且整个事物中的操作要么全部失败,要么全部成功;
一致性 的意思就是 数据从一种状态转移至另一种状态,其数据完整没有被破坏;如上例子小知扣除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' 复制代码
操作示例如下:
使用如下语句可以对 自动提交进行设置
关注知识追寻者: