MySQL 事务处理语言 TCL

news/2024/11/23 2:35:23/

文章目录

  • 事务处理语言 TCL
    • 事务简介
    • 事务控制
    • 并发事务的隔离挑战
      • 脏读
      • 不可重复读
      • 幻读
    • 事务的隔离级别
      • 未提交读(READ-UNCOMMITED)
      • 提交读(READ COMMITED)
      • 可重复读(REPEATABLE READ)
      • 可串行化(SERIALIZABLE)


事务处理语言 TCL

在这里插入图片描述

在进行数据操作的时候,往往会有很多不确定事件发生,这些事情通常都具有破坏性,导致数据不一致或者缺失等等。

有人在银行 ATM 机上取 5000 现金,点钱过程中突然断电了,只取出一部分,而卡中余额提示已经扣掉了 5000,怎么办?这种时候,我们就需要一种机制来保证数据结果的一致性。在数据库中,这个机制就叫做事务。

事务简介

事务(Transaction)是数据库操作的最小工作单元,是作为单个逻辑执行的一系列操作(比如上述中的输入取款金额,得到现金,取回磁卡等操作)的集合;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行。事务是不可再分割的。

事务具有四大特征,即常说的 ACID:

  1. 原子性(Atomicity):事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做。
  2. 一致性(Consistency):事务执行的前后数据都处于合法状态,不会违背任何的数据完整性和逻辑的正确性,这就是“一致”的意思。以转账为例,转出账户的钱减少,但转入账户的钱没有增加,就不符合一致性。再以转账为例,无论多少个账户,多少个并行事务,其总数必然是一致的。原子性有助于保证数据的一致性,但不能完全保证。
  3. 隔离性(Isolation):一个事务的执行不能被其它事务所干扰,即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。换句话说,事务之间感知不到彼此的存在。
  4. 持续性(Durability):又叫永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

事务控制

事务的控制是通过一系列控制语句来完成的,代表着事务的各个阶段。常用的控制语句如下表所示:

语句说明
BEGIN(START TRANSACTION)开始一个新的事务
SAVEPOINT设置事务的保存点
COMMIT提交事务
ROLLBACK回滚当前事务到初始状态,撤销提交前的操作
ROLLBACK TO SAVEPOINT name回滚当前事务到指定保存点 name,并撤销保存点后的操作
SET AUTOCOMMIT设置当前连接是否自动提交事务,1 表示启用自动提交,0 表示禁用自动提交
RELEASE SAVEPOINT释放保存点
SET TRANSACTION设置事务的隔离级别

查看当前事务是否设置了自动提交,其 SQL 语句如下:

select @@autocommit;

输出结果:

MariaDB [world]> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.000 sec)

该值为 1,即 MySQL 默认启用事务的自动提交模式,不用再输入提交命令。

为了突出事务的特点,笔者把事务提交方式设置为禁止自动提交。其 SQL 语句如下:

set autocommit = 0;

输出结果:

MariaDB [world]> set autocommit = 0;
Query OK, 0 rows affected (0.000 sec)

查看修改结果:

select @@autocommit;

输出结果:

MariaDB [world]> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.000 sec)

利用 DELETE 子句,把 city 表中 ID 为 1 的记录给删除掉,其 SQL 语句如下:

delete from city where id = 1;

输出结果:

MariaDB [world]> delete from city where id = 1;
Query OK, 1 row affected (0.000 sec)

接着查询 id 为 1 的记录此时是否存在,使用 SQL 语句如下:

select * from city where id = 1;

输出结果:

MariaDB [world]> select * from city where id = 1;
Empty set (0.000 sec)

从结果看,数据已经被删除,但此时事务并没有提交。所以当前对数据的操作还没有完全写入到数据库中,使用 ROLLBACK 来回滚事务,返回到该操作之前,其 SQL 语句如下:

rollback;

输出结果:

MariaDB [world]> rollback;
Query OK, 0 rows affected (0.001 sec)

再次查看 id 为 1 的记录是否存在,结果如下:

select * from city where id = 1;

输出结果:

MariaDB [world]> select * from city where id = 1;
+----+-------+-------------+----------+------------+
| ID | Name  | CountryCode | District | Population |
+----+-------+-------------+----------+------------+
|  1 | Kabul | AFG         | Kabol    |    1780000 |
+----+-------+-------------+----------+------------+
1 row in set (0.000 sec)

通过回滚操作,数据又回来了。只要在正式提交之前,都可以进行数据回滚。提交事务使用的控制语句是 COMMIT ,其 SQL 语句如下:

commit;

输出结果:

MariaDB [world]> commit;
Query OK, 0 rows affected (0.000 sec)

确保数据的修改无误后,使用 COMMIT 来提交数据,我们也把这种方式称为显示提交。 下面,演示一个比较简单的例子,来说明一下事务保存点的设置以及回滚等操作。

  1. 开始事务
  2. 然后在 city 表中插入一条记录
  3. 接着设置一个保存点
  4. 再插入一条记录
  5. 查看表内容变化情况
  6. 然后回滚到保存点
  7. 再次查看表内容
  8. 最后回滚到事务开始的地方
  9. 查看表内容,此时表内容和事务开始前是一样的,没有任何新的记录增加。

上面事务步骤翻译成 SQL 语句如下:

begin;

输出结果:
在这里插入图片描述

insert into city values(null,'test1','AFG','test1',101);

输出结果:
在这里插入图片描述

savepoint s1;

输出结果:
在这里插入图片描述

此处设置了保存点,取名为 s1。

insert into city values(null,'test2','AFG','test2',10001);

输出结果:
在这里插入图片描述

select * from city where countrycode = 'AFG';

输出结果:
在这里插入图片描述

此时可以看到,新插入的两条记录都显示出来了。

rollback to savepoint s1;

输出结果:
在这里插入图片描述

回滚到保存点 s1 位置处。

select * from city where countrycode = 'AFG';

输出结果:
在这里插入图片描述

可以看到设置保存点 s1 之后的操作(插入的第二条记录)已经实现回滚,数据没有了。

rollback;

输出结果:
在这里插入图片描述

此时回滚到了事务开始的地方,即 begin 位置处。

select * from city where countrycode = 'AFG';

输出结果:
在这里插入图片描述

再次查看结果,可以发现 city 表的内容和事务开始之前一模一样,没有任何变化。

并发事务的隔离挑战

事务并发是指多个事务同时对同一个数据进行操作。并发事务未做到隔离性,会带来以下问题:

脏读

一个事务读取到另一事务未提交的更新数据。当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中。这时,另外一个事务也访问这个数据,然后读到了修改后的数据,这个数据就是脏数据,依据脏数据所做的操作也是不正确的。例如 T1 开启了一个长事务,在较早的时间删除了一条记录,此时事务 T2 正好要统计表中记录总数,会少统计一条,随后 T1 事务发现删错了,进行了回滚操作,再随后 T2 事务再次统计,发现前后数据不一致。这显然违背了隔离性原则。

简单来说,脏读是指读到了未持久化的数据。

不可重复读

在同一事务中,多次读取同一数据返回的结果有所不同。换句话说,后续读取读到的是另一事务已提交的更新数据。例如 T1 开启了一个较长的事务,在较早的时间读取了一个数据,在中间另一个事务 T2 更改了数据并提交,随后 T1 再次读取但获得了新版本的数据,这时在同一个事务中多次读取同一数据却得到不同结果,这种现象就是不可重复读。显然,这也不符合隔离性原则。

幻读

在同一个事务中,以同样的条件进行范围查询,两次获得的记录数不一样。事务 T1 先执行了一次查询,然后事务 T2 新插入一行记录,接着 T1 使用相同的查询再次对表进行检索时,会发现这条出来的记录。这突然出现的记录就如一个“幻像”。 与“不可重复读”不同的是,幻读专指新插入的行。

那么如何来预防这些问题呢?

事务的隔离级别

为了防止上述问题,我们要对事务进行隔离。事务隔离有四个级别:

未提交读(READ-UNCOMMITED)

该级别的隔离性最弱,但并发性最好;事务中的修改,即使没有提交,对其他事务也都是可见的。也就是说事务可以读取未提交的数据,即产生脏读现象。

提交读(READ COMMITED)

一个事务提交后,它的变更才能被其他事务看到。大多数据库系统的默认级别,但 MySQL 不是。该级别的隔离可杜绝脏读,但仍会发生不可重复读。

可重复读(REPEATABLE READ)

MySQL 中事务的默认隔离级别。与“不可重复读”相反,“可重复读”是指在同一事务中多次读取同一数据时得到的都是事务开始那个时间点的数据版本,也可以理解为事务开始时对数据库拍了一个快照,后续操作都是在快照基础上进行的,自然不会读到别的事务的提交结果。

该级别直接针对不可重复读,但不能解决幻读。

可串行化(SERIALIZABLE)

当两个事务间存在读写冲突时,数据库通过加锁强制事务串行执行,解决了前面说的所有问题(脏读、不可重复读、幻读)。是最高的隔离级别。

名称含义脏读不可重复读幻读
未提交读一个事务提交前,它的变更就已经能被其他事务看到
读提交一个事务提交后,它的变更才能被其他事务看到×
可重复读未提交的事务的变更不能被其他事务看到,同时一次事务过程中多次读取同样记录的结果是一致的。××
可串行化当两个事务间存在读写冲突时,数据库通过加锁强制事务串行执行×××

http://www.ppmy.cn/news/211002.html

相关文章

命名管道详解

一、命名管道 1、命名管道与匿名管道一个很显著的区别是:匿名管道只能在有血缘关系的进程间进行通信,但命名管道可以让两个毫无关系的进程进行通信。 2、如果我们想在不相关的进程间交换数据,我们可以用到FIFO文件来进行通信,这…

Redis高级数据结构之GEO

GEO的介绍 Redis3.2版本提供了GEO地址位置信息定位的功能。支持存储地理位置信息来实现诸如摇一摇,附近位置这类地理位置信息的功能。 Redis也是使用业界比较通用的地理位置距离排序算法GeoHash算法。将二维的经纬度坐标数据映射到一维的整数,将所有元素…

数据挖掘 基础知识 收集

A Tutorial on Clustering Algorithms-聚类小知识 俗话说:“物以类聚,人以群分”,在自然科学和社会科学中,存在着大量的分类问题。所谓类,通俗地说,就是指相似元素的集合。聚类分析又称群分析,…

朴素贝叶斯(西瓜数据集分类,社区恶意留言分类,垃圾邮件分类,新浪新闻分类),AODE分类器 代码实现

朴素贝叶斯(西瓜数据集分类,社区恶意留言分类,垃圾邮件分类,新浪新闻分类),AODE分类器 代码实现 以下代码为本人学习后,修改或补充后的代码实现,数据集和原代码请参考:h…

宏定义编程软件_什么是计算机编程? 定义软件开发。

宏定义编程软件 My five year old son, Ramy, approached me one day while I was working from home and asked, “What are you doing Mama?” 我五岁的儿子拉米有一天在我在家工作时走近我,问道:“你在做什么妈妈?” “I’m working,”…

二代芯片获认可又拿到上亿元融资的深聪智能,正在逐步构筑自己的竞争壁垒...

数据智能产业创新服务媒体 ——聚焦数智 改变商业 日前,思必驰旗下的芯片设计企业上海深聪半导体有限责任公司(以下简称“深聪智能”)获得上亿元人民币的A轮融资,投资方包括雅迪科技集团、珠海大横琴集团、元禾控股、苏州工业园区…

多线程事务回滚方法

多线程事务回滚方法 介绍案例演示线程池配置异常类实体类控制层业务层mapper工具类验证 解决方案使用sqlSession控制手动提交事务SqlSessionTemplate注入容器中改造业务层验证成功操作示例业务层改造 介绍 1.最近有一个大数据量插入的操作入库的业务场景,需要先做一…

1.JSJQ课程期末复习之复习JS

1.加强for var bnew Array(10);var a["aaa","bbb"];for(var i in a){}2.continue和break的区别 continue本次循环continue关键字下面不执行了,可以继续循环(跳本次循环,继续本次循环) break直接跳出循环 3.常见系统函数 var aparseInt("str");/…