MySQL_Sql_打怪升级_进阶篇_进阶15: TCL事物控制语言
进阶15: TCL事物控制语言
15.1 事物控制语言介绍
TCL Transaction Control Language 事务控制语言
事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
案例:转账
张无忌 1000
赵敏 1000
update 表 set 张三丰的余额=500 where name='张无忌'
意外
update 表 set 郭襄的余额=1500 where name='赵敏'
15.2 事务的特性
ACID
原子性:Atomicity 一个事务不可再分割,要么都执行要么都不执行
一致性:Consistncy 一个事务执行会使数据从一个一致状态切换到另外一个一致状态
隔离性:Isolation 一个事务的执行不受其他事务的干扰
持久性:Durability 一个事务一旦提交,则会永久的改变数据库的数据.
15.3 事务的创建
①隐式事务:事务没有明显的开启和结束的标记
比如 insert、update、delete语句
delete from 表 where id =1;
②显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用
查看事务默认开启状态 (默认是开启)
select @@autocommit;
show variables like '%autocommit%';
set autocommit=0;
步骤1:开启事务
set autocommit=0;
start transaction; 可选的
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
...
步骤3: 结束事务
commit; 提交事务
rollback;回滚事务
savepoint 节点名; 设置保存点
15.4 事务的隔离级别
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
① 脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段.
之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
②不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段.
之后, T1再次读取同一个字段, 值就不同了.
③幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中 插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
事务的隔离性:
避免并发出现的问题,数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响, 避免各种并发问题,一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
数据库提供的 4 种事务隔离级别:
隔离级别 | 描述 |
---|---|
READ UNCOMMITTED | (读未提交) 允许事务读取未被其他事物提交的变更.脏读,不可重复读和幻读的问题都会出现 |
READ COMMITED | (读已提交数据) 只允许事务读取已经被其它事务提交的变更.可以避免脏读,但不可重复读和幻读问题仍然可能出现 |
REPEATABLE READ | (可重复读) 确保事务可以多次从一个字段中读取相同的值.在这个事务持续期间,禁止其他事物对这个字段进行更新.可以避免脏读和不可重复读,但幻读的问题仍然存在. |
SERIALIZABLE | (串行化) 确保事务可以从一个表中读取相同的行.在这个事务持续期间,防止其他事务对该表执行插入,更新和删除操作.所有并发问题都可以避免,但性能十分低下. |
Oracle 支持的 2 种事务隔离级别:READ COMMITED,SERIALIZABLE。 默认的事务隔离级别为: READ COMMITED
Mysql 支持的 4 种事务隔离级别。默认的事务隔离级别为: REPEATABLE READ
隔离级别/并发问题 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted | 会出现 | 会出现 | 会出现 |
read committed | 不出现 | 会出现 | 会出现 |
repeatable read | 不出现 | 不出现 | 会出现 |
serializable | 不出现 | 不出现 | 不出现 |
查看隔离级别 select @@transaction_isolation;
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
设置隔离级别
set session|global transaction_isolation= 隔离级别;
#例如:设置成读未提交
set global transaction_isolation='read-uncomminted';
read uncommitted
read commited
repeatable read
serializable
15.5 事务的演示
0.创建相关测试环境
SHOW VARIABLES LIKE 'autocommit';
SHOW ENGINES;
DROP TABLE IF EXISTS account;
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
balance DOUBLE
);
INSERT INTO account (username,balance)VALUES(”张无忌,1000),('赵敏',1000);
1.演示事务的使用步骤
①开启事务
SET autocommit=0;
START TRANSACTION;
②编写一组事务的语句
UPDATE account SET balance = 1000 WHERE username='张无忌';
UPDATE account SET balance = 1000 WHERE username='赵敏';
③结束事务
#ROLLBACK;
COMMIT;
SELECT * FROM account;
2.演示事务对于delete和truncate的处理的区别
#delete 删除可以回滚
SET autocommit=0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK;
#truncate 删除无法回滚
SET autocommit=0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK;
3.演示save point 的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a; #设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a; #回滚到保存点
SELECT * FROM account;
4.演示事务的脏读,不可重复读,幻读
操作示例.演示(1,2,3)这几种级别:
1.RU Read-uncommitted
调整参数:
set global transaction_isolation='read-uncomminted';
①脏读的例子.
sessinon1:
begin;
updata city set name='oldli' where id=2;
sessinon2:
begin;
select * from city;
说明:
一句话: 读到未提交的脏页.
比如说,有两个会话,会话A和会话B,当会话A开启事务begin时,执行一条DML语句update一条数据,并未完成commint,此时的会话B,也开启一个事务begin后,执行的一条语句是select, 发现的问题是 能看到刚刚会话A执行的update的内容,这是不允许的, 这种情况称为"脏读"
应用场景:
脏读生产中是不可以出现的.
②不可重复读数据
sessinon1:
begin;
updata city set name='oldli' where id=2;
commit;
sessinon2:
begin;
select * from city;
commint;
说明:
一句话: 在同一事务内,做同一样的操作,不同时间段得到的结果是不一致的情况,称为不可重复读.
比如说,有两个会话,会话A和会话B,当会话A开启多个事务begin时,多次执行一条不同DML语句update数据,并完成commint,此时的会话B,执行select的时候,会发现每次查询的结果,都不一致,这种情况称为"不可重复读"
应用场景:
对于事务的隔离性,数据最终一致性要求比较高的业务是不允许出现的. 如果能容忍的话 可以调整RC模式.
③幻读
sessinon1:
准备环境:
create table test (id int, num int, name varchar(20));
insert into test values(1,10,'oldli'),(2,20,'lizicheng'),(3,30,'weichunxue');
事务正在做批量更新
begin;
update test set num=100 where num>10;
commit;
select * from test;
sessinon2:
事务插入一条数据
begin;
insert into test values(40,333,'aaa');
commit;
select * from test;
说明:
一句话: 更新insert数据的时候,出现换行的数据.
比如说,有两个会话,会话A和会话B,当会话A开启事务begin时,执行批量的DML语句update数据,完成commint,此时的会话B,执行insert的时候,也完成commint,当会话A和会话B执行select的时候,会发现会话A多出一行(换行)的数据,(这个数据是会话B insert事务进来的)并不是最终想要的结果,这种情况称为"幻读"
小结:
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
脏读: update 事务未提交,读到脏页数据
不可重复读: update 事务提交,一定时间段内的数据不一致
幻读: insert 事务提交,数据会多出一行.