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 事务提交,数据会多出一行.
原文地址:https://www.cnblogs.com/liych/p/13929569.html