13 —— TCL(事务控制语言)

一、基础

1、事务:

是指一个或一组SQL语句组成的执行单元,在该单元中,每个SQL语句相互依赖,该执行单元要么全部执行,要么全不执行。如果单元中的某条SQL语句执行失败或产生错误,则整个单元将会回滚。所有受影响的数据将返回到事务开始以前的状态。

2、MySQL中的存储引擎:

  • 在MySQL中的数据用各种不同的技术存储在文件中
  • 通过 show engines 来查看MySQL支持的存储引擎
  • 在MySQL中用的最多的存储引擎有:innodb,myisam,memory等。其中 innodb 支持事务,另外两个不支持事务

3、事务的属性(ACID):

  • 原子性(atomicity):指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
  • 一致性:事务必须使数据库从一个一致 性状态变换到另外一个一致性状态
  • 隔离性:事务的隔离性是指一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间相互不能干扰。
  • 持久性:指事务一旦被提交,它的改变是持久性的

4、事务的创建

  • 隐式事务:事务没有明显的开启和结束标记。如insert、update、delete等语句
  • 显示事务:事务具有明显的开启和结束标记。【前提:必须先设置自动提交功能为禁用状态】

5、自动提交功能的开启与禁用

# 禁用自动提交功能,0表示禁用。
set autocommit=0;

# 开启自动提交功能
set autocommit=1;

# 查看事务自动提交功能的状态
show variables like 'autocommit';

6、使用事务的语法

set autocommit=0;      # 开启事务,将自动提交关闭
[start transaction;]   # 当上面设置了autocommit=0,所以该语句可以省略
编写事务中的SQL语句(一般指:select、insert、update、delete)
commit;     # 提交事务
rollback;   # 回滚事务

二、单个事务的应用

  有如下表:

  

1、Tony01 向 Tom01 转账 500元的事务控制语言。【必须要保证Tony01 转账成功,且Tom01收款成功,因此需要用事务控制语言】

# 开启事务
SET autocommit=0;
START TRANSACTION;
# 编写一组事务的语句。在执行结束事务语句之前,下面的操作只是暂存到内存
# 等结束事务语句来决定是否要提交到磁盘或者回滚到之前的状态
UPDATE stuInfo SET money=1500 WHERE sname='Tony01';
UPDATE stuInfo SET money=3500 WHERE sname='Tom01';
# 结束事务
COMMIT;  # 将操作进行提交到磁盘文件,使其永久生效

    

2、Tom01 向 Tony01 转账1000元,顺利完成后应该是 Tony01 有2500元,Tom01 有2500元。现在使用回滚来测试

# 开启事务
SET autocommit=0;
START TRANSACTION;
# 编写一组事务的语句
UPDATE stuInfo SET money=2500 WHERE sname='Tony01';
UPDATE stuInfo SET money=2500 WHERE sname='Tom01';
# 结束事务
ROLLBACK;       # 使用回滚,则上面的事务语句都不会生效,数据仍保持之前的状态

    结果如下图,显示事务语句并未生效

   

 3、savepoint 的使用(保存点一般要和rollback 搭配使用,用于回滚到某位置),操作如下表 stuinfo

SET autocommit=0;
START TRANSACTION;
DELETE FROM stuinfo WHERE id=1;
SAVEPOINT apoint;	# 设置保存点
DELETE FROM stuinfo WHERE id=2;
ROLLBACK TO apoint;	# 回滚到apoint 点

   由于回滚到 apoint 点的,则相当于id=2的语句未执行,id=1的语句被执行了。显示结果如下:

   


三、多个事务:数据库的隔离

1、基础简介:

(1)、对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。如:

  • 脏读:对于两个事务 T1,T2。若T1 读取了已经被T2更新,但还没有被提交的字段之后,若T2 回滚,T1读取的内容就是临时且无效的。
  • 不可重复读:对于两个事务 T1,T2。若T1 读取了一个字段,然后T2更新了该字段之后,T1 再次读取同一个字段,值就不同了。
  • 幻读:对于两个事务T1,T2。若T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行之后,如果T1再次读取同一个表,就会有多出几行。

(2)、数据库事务的隔离:通过设置数据库系统的隔离级别来避免出现上面的各种并发问题。MySQL支持4种事务隔离级别,默认的隔离级别为:repeatable read

事务隔离级别 作用
read uncommitted 允许事务读取未被其它事务提交的变更。脏读、不可重复读和幻读的问题会出现。
read committed 只允许事务读取已经被其它事务提交的变更,可避免脏读,但不可重复读和幻读存在。
repeatable read 确保事务可以多次从一个字段中读取相同的值,在这事务持续期间,禁止其它事务对该字段进行更新。可避免脏读、不可重复读和幻读的问题。
serializable 确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其它事务对该表执行插入、更新和删除操作。所有并发问题都可以避免,但性能十分低下。

 (3)、查询数据库当前的隔离级别:

select @@transaction_isolation;

   

(4)、设置数据库的隔离级别语法为:

set session transaction isolation level 事务隔离级别;

2、不同隔离级别的应用实例 

1、以最低的事务隔离级别: read uncommitted 来操作下表 stuinfo 中的数据,展示多事务并发的问题:

      

(1)、在一个事务(事务1)中修改数据

set session transaction isolation level read uncommitted;  # 设置事务隔离级别为:read uncommitted

set autocommit=0;  # 开启事务
update stuinfo set sname='kuko' where id=1;    # 修改事务中的数据

(2)、重新开一个CMD窗口登陆MySQL账户,然后设置好其事务隔离级别,再开启一个事务(事务2)来访问上面事务1中操作的数据(事务1尚未结束),此时会发现得到的是事务1中还未提交的临时数据,如果上面的事务最后以回滚来结束的话,则事务2再访问时又会出现不同的数据。从而出现脏读和幻读的并发问题

set session transaction isolation level read uncommitted;

use students;    # 进入students库中
select * from stuinfo;  # 查看该库中的 stuinfo 表的数据

   此时结果为事务1操作后的临时数据,如下 sname 已经由 Tony01 修改为 kuko

   

(3)、分别结束事务1和事务2。如果事务1最后以 commit 结束,则事务2得到的就是以上的结果,但如果事务1最后以 rollback 结束,则次事务2再次查看数据时,结果将是未修改之前的 ,这将会与上一次查看的结果不同,从而出现脏读的现象。

2、以事务隔离级别:read committed 来操作表 stuinfo 中的数据(stuinfo 表如下图所示)

     

(1)、在 cmd 窗口设置事务隔离级别为 read committed ,并开启事务1 来操作数据

set session transaction isolation level read committed;

set autocommit=0;
update stuinfo set sname='john' where id=1;

(2)、在另一个 cmd窗口设置事务隔离级别为 read committed ,并开启事务2 查看表的数据

set session transaction isolation level read commited;

set autocommit=0;
select * from stuinfo;

    此时由于事务1还未结束,所以事务1中的数据只是临时数据,未提交到磁盘。所以事务2此时读取的数据是还未修改过的数据,这样就避免了脏读。如下图所示:

    

(3)、提交修改来结束事务1,然后再通过事务2来读取数据,结果如下图。此时读取的数据为事务1修改后的数据,由于这两次读取的数据不同,从而出现了 不可重复读的现象。最后提交事务2来结束。

    

3、以事务隔离级别:repeatable read 来操作表 stuinfo 中的数据(stuinfo 表如下图所示)

      

(1)、在 cmd 窗口设置事务隔离级别为 repeatable read ,并开启事务1 来修改数据

set session transaction isolation level repeatable read; # 设置隔离级别

set autocommit=0;
update stuinfo set sname='Kity' where id=1;

(2)、在另一个 cmd窗口设置事务隔离级别为 repeatable read ,并开启事务2 查看表的数据。结果如下图

set session transaction isolation level repeatable read;

set autocommit=0;
select * from stuinfo;

     

(3)、提交事务1,此时事务2还未提交,在事务2中再查看数据,结果还是原来的数据,如下图

    

(4)、再提交事务2(此时事务1和事务2都已提交),在事务2所在的 CMD 窗口中再次查看数据,此时看到的数据才是事务1修改后的,如下图所示

   

4、以事务隔离级别:serializable 来操作表 stuinfo 中的数据,其作用类似于上面的 repeatable read 

发布了213 篇原创文章 · 获赞 48 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Jeffxu_lib/article/details/102415458