SQL Server从入门到项目实践(超值版)读书笔记 28

第15章 事务与锁的应用

🎉学习指引

SQL server中提供了多种数据完整性的保证机制,如触发器、事务和锁等,本章就来介绍SQL SERVER的事务管理与锁机制,主要内容包括事务的类型和应用、锁的作用与类型、锁的应用等。

15.1 事务管理

事务是SQL SERVER中的基本工作单元,它是用户定义的一个数据库操作序列,事务管理的主要功能是为了保证一批相关数据库中数据的操作能全部被执行完成,从而保证数据的完整性。

15.1.1 事务的概念

事务用于保证数据的一致性,它由一组相关的DML(数据操作语言)语句组成,该组DML语句要么全部成功,要么全部失败。

在SQL SERVER中,事务要有非常明确的开始和结束点,SQL SERVER中的每一条数据操作语句,例如SELECT\INSERT\UPDATE和DELETE都是隐式事务的一部分。即使只有一条语句,系统也会把这条语句当作一个事务,要么执行所有语句,要么什么都不执行。

事务开始之后,事务中所有的操作都会写到事务日志中,写到日志中的事务一般有两种:

  1. 针对数据的操作,例如插入、修改和删除,这些操作对象是大量的数据;
  2. 针对任务的操作,例如创建索引。

当取消这些事务操作时,系统自动执行这种操作的反操作,保证系统的一致性。系统自动生成一个检查点机制,这个检查点周期地检查事务日志。如果在事务日志中,事务全部完成,那么检查点事务日志中的事务提交到数据库中,并且在事务日志中做一个检查点提交标识;如果在事务日志中,事务没有完成,那么检查点不会将事务日志中的事务提交到数据库,并且在事务日志中做个一检查点未提交的标识。事务的恢复及检查点保证了系统的完整和可恢复。

例如:网上转账就是一个用事务来处理的典型案例,它主要分为三步:

  1. 在原账号中减少转账金额;
  2. 在目标账号中增加转账金额;
  3. 在事务日志中记录该事务

这样可以保证数据的一致性,这三步如果有一部失败,则整个事务都会回滚,所有的操作都将撤销,目标账号和原账号中的金额都不会发生变化。

15.1.2 事务的类型

SQL SERVER中,事务主要可以分为自动提交事务,隐式事务,显示事务和分布式事务四种类型,介绍如下:

  1. 自动提交事务:每条单独语句都是一个事务。
  2. 隐式事务:前一个事务完成时新事务隐式启动,每个事务仍以COMMIT或ROLLBACK语句显示结束。
  3. 显示事务:每个事务均以BEGIN TRNSACTION语句显示开始,以COMMIT或ROLLBACK语句显示结束。
  4. 分布式事务:跨越多个服务器的事务。
15.1.3 事务的属性

事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有4个属性,称为原子性(Atomic)、一致性(Consistent)、隔离性(Isolated)和持久性(Durable),简称ACID属性,只有这样才能构成一个事务。

  1. 原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
  2. 一致性:事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构都必须是正确的。
  3. 隔离性:由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据,这称为可串行性。因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行时的状态相同。
  4. 持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
15.1.4 建立事务应遵循的原则

在建立事务时,应该遵循以下的原则:

  1. 事务中不能包含以下语句:ALTER DATABASE\DROP DATABASE\ALTER FULLTEXT CATALOG\DROP FULLTEXT CATALOG\ALTER FULLTEXT INDEX\DROP FULLTEXT INDEX\BACKUP\RECONFIGURE\CREATE DATABASE\RESTORE\CREATE FULLTEXT CATALOG\UPDATE STATISTICS\CREATE FULLTEXT INDEX。
  2. 当调用远程服务器上的存储过程时,不能使用ROLLBACK TRANSACTION语句,不可执行回滚操作。
  3. SQL SERVER不允许在事务内使用存储过程建立临时表。
15.1.5 事务管理的常用语句

SQL SERVER中常用的事务管理语句包含如下:

  1. BEGIN TRANSACTION:创建一个事务
  2. COMMIT TRANSACTION:提交事务
  3. ROLLBACK TRANSACTION:事务失败时执行回滚操作
  4. SAVE TRANSACTION:保持事务

📢注意:BEGIN TRANSACTION和COMMIT TRANSACTION同时使用,用来标识事务的开始和结束。

15.1.6 事务的隔离级别

事务具有隔离性,不同事务中所使用的时间必须要和其他事务进行隔离,在同一时间可以有很多个事务正在处理数据,但是每个数据在同一时刻只能有一个事务进行操作。如果将数据锁定,使用数据的事务就必须要排队等待,可以防止多个事务互相影响。但是如果有几个事务因为锁定了自己的数据,同时又在等待其他事务释放数据,则会造成死锁。

为了提高数据的并发使用效率,可以为事务在读取数据时设置隔离状态,SQL SERVER中事务的隔离状态由低到高可以分为5个级别。

  1. READ UNCOMMITTED级别:该级别不隔离数据,即使事务正在使用数据,其他事务也能同时修改或删除该数据。在READ UNCOMMITTED级别运行的事务,不会发出共享锁来防止其他事务修改当前事务读取的数据。
  2. READ COMMITTED级别:指定语句不能读取已由其他事务修改但尚未提交的数据。这样可以避免脏读。其他事务可以在当前事务的各个语句之间更改数据,从而产生不可重复读取和幻象数据。在READ COMMITTED事务中读取的数据随时都可能被修改,但已经修改过的数据事务会一直被锁定,直到事务结束为止。该选项是SQL SERVER的默认设置。
  3. REPEATABLE READ级别:指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都不能在当前事务完成之前修改由当前事务读取的数据。该事务中的每个语句所读取的全部数据都设置了共享锁,并且该共享锁一直保持到事务完成为止。这样可以防止其他事务修改当前事务读取的任何行。
  4. SNAPSHOT级别:指定事务中任何语句读取的数据都将是在事务开始时便存在的数据事务上一致的版本。事务只能识别在其开始之前提交的数据修改。在当前事务执行的语句将看不到在当前事务开始以后由其他事务所做的数据修改。其效果就好像事务中的语句获得了已提交数据的快照,因为该数据在事务开始时就存在。除非正在恢复数据库,否则SNAPSHOT事务不会再读取数据时请求锁。读取数据的SNAPSHOT事务不会阻止其他事务写入数据。写入数据的事务也不会阻止SNAPSHOT事务读取数据。
  5. SERIALIZABLE级别:将事务所要用到的时间全部锁定,不允许其他事务添加、删除、修改数据,使用该等级的事务并发性最低,要读取同一数据的事务必须排队等待。

可以使用SET语句更改事务的级别:

sql 复制代码
SET TRANSACTION ISOLATION LEVEL
{
    READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SNAPSHOT
    | SERIALIZABLE
} [;]
15.1.7 事务的应用案例

限定students表中最多只能插入6条学生记录,如果表中插入的人数大于6人,则插入失败。

首先,为了对比执行结果,先查看students表中当前的记录:

sql 复制代码
SELECT * FROM students

执行语句后可看到,表内目前有3条记录。接下来输入下面的语句:

sql 复制代码
BEGIN TRANSACTION --事务开始
INSERT INTO students VALUES(1004,'黄忠',25)
INSERT INTO students VALUES(1005,'魏延',45)
INSERT INTO students VALUES(1006,'马超',30)
INSERT INTO students VALUES(1007,'姜维',29)
--插入4行记录
DECLARE @studentcount int=0 --定义一个变量
SELECT @studentcount=select count(*) from students --把当前表内记录的行数赋值给变量
IF @studentcount>6 --如果变量大于6
    BEGIN
        ROLLBACK TRANSACTION --回滚所有操作
        PRINT '数量太多,插入失败!' --在屏幕打印提示文字
    END
ELSE --否则
    BEGIN
        COMMIT TRANSACTION --提交事务
        PRINT '插入成功!' --打印提示
        select * from students --读取表里所有记录
    END

执行后,数据库提示:

我们修改上面的语句,将IF判断条件中的数量增加至10条,执行后结果如下:

该段代码中使用BEGIN TRANSACTION定义事务的开始,向students表中插入4条数据,插入完成后,判断students表中总记录数是否大于6,如果成立,则插入失败,并使用ROLLBACK TRANSACTION撤销所有的操作,反之,则提交事务,将所有新的学生记录插入到students表中。

相关推荐
楚韵天工3 小时前
宠物服务平台(程序+文档)
java·网络·数据库·spring cloud·编辑器·intellij-idea·宠物
李白你好5 小时前
一款专业的多数据库安全评估工具,支持 **PostgreSQL、MySQL、Redis、MSSQL** 等多种数据库的后渗透操作
数据库·mysql·postgresql
恋红尘5 小时前
Mysql
数据库·mysql
paishishaba5 小时前
数据库设计原则
数据库
曹牧6 小时前
oracle:NOT IN
数据库·oracle
爬山算法6 小时前
Redis(66)Redis如何实现分布式锁?
数据库·redis·分布式
Super Rookie7 小时前
MongoDB 自动化脚本安装方案
数据库·mongodb·自动化
Code哈哈笑7 小时前
【MongoDB 基本语法】数据库和集合的基本操作--探秘 MongoDB
数据库·mongodb
恋红尘7 小时前
Redis面试八股
数据库·redis·面试