SqlServer事务详解(事务隔离性和隔离级别详解)(上)

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: SqlServer事务详解(事务隔离性和隔离级别详解)

概述

  不少人对于事务的使用局限于begin transaction:开始事务、commit transaction:提交事务、rollback transaction:回滚事务的初步运用。

并且知道使用事务后, 事务中所有操作命令必须作为一个整体提交或回滚,如果事务中任何操作命令失败,则整个事务将因失败而回滚。

  除了这个概念性的东西后,其他就不怎么知道了,比如事务的隔离性,具体怎么隔离、有几种隔离方式、执行顺序是什么。

我们今天来聊一聊这一块的内容(主要是事务的隔离性)。


 

什么是事务(定义)

  事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。

事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

事务是作为单个逻辑单元执行的一系列操作,它是一个不可分割的工作逻辑单元。它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行。

 


事务的4个特性(特性)

 

事务是恢复和并发控制的基本单位。

 

事务应该具有4个属性:原子性一致性隔离性持久性。这四个属性通常称为ACID特性。

 

原子性(atomicity)

  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,

因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

 

一致性(consistency)

  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

比如转账,假设张三和李四两个人的钱加起来一共是2000,那么不管张三和李四之间怎么转账,转几次账,事务结束后两个人的钱加起来还得是2000,这就是事务的一致性。

 

隔离性(isolation)

  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

 

持久性(durability)

持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

  在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,

即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。


事务的分类 (分类)

事务分为三类:显式事务隐式事务自动提交事务

(1) 显式事务:用 begin transaction 明确指定事务的开始,由 commit transaction 提交事务、rollback transaction 回滚事务到事务结束。

(2) 隐式事务:通过设置 set implicit_transactions on 语句,将隐式事务模式设置为打开。

当以隐式事务模式操作时,不必使用 begin transaction 开启事务,当一个事务结束后,这个模式会自动启用下一个事务,

只需使用 commit transaction 提交事务或 Rollback Transaction 回滚事务即可。

(3) 自动提交事务: 这是 SQL Server 的默认模式,它将每条单独的 T-SQL 语句视为一个事务。如果成功执行,则自动提交。如果错误,则自动回滚。


 

简单事务应用示例

我们先看一个简单的应用。

--这里指定不指定事务名称均可
BEGIN TRANSACTION tran_UpdateTable --开启事务(tran_UpdateTable:事务名称)
DECLARE @tran_error int;--定义错误变量
SET @tran_error=0;        --错误变量的初始值为0
--使用 try catch进行错误捕捉
BEGIN TRY
UPDATE a_Students SET Name='孙悟空' WHERE Number='100001';
UPDATE a_StudentsScore SET C# ='我是分数,应该是数字' WHERE Number='100001';
END TRY
BEGIN CATCH
set @tran_error=@tran_error+1; --(计算捕捉到的错误数)加分号或不加都能正常执行
END CATCH
--判断是否有执行错误
IF(@tran_error>0)
    BEGIN 
        ROLLBACK TRANSACTION tran_UpdateTable  --执行出错,回滚事务(tran_UpdateTable:指定事务名称)
        PRINT '有【'+CONVERT(VARCHAR(50),@tran_error)+'】条执行失败,进行回滚:'; 
    END 
ELSE
    BEGIN
        COMMIT TRANSACTION tran_UpdateTable --没有异常,提交事务(tran_UpdateTable:指定事务名称)
        --事务执行成功后,查看修改后的数据
        SELECT  s.Number ,
        s.Name ,
        sc.ClassName ,
        ss.C# ,
        ss.SqlDB ,
        ss.Java ,
        ss.Python
        FROM    a_Students s
        INNER JOIN a_StudentClass sc ON s.ClassId = sc.ClassId
        INNER JOIN a_StudentsScore ss ON s.Number = ss.Number
        WHERE s.Number='100001'
    END 

上面事务表示:根据学生编号修改学生姓名和学生学科C#的成绩,如果有任何一条执行失败则全部返回不执行,否则执行修改成功。


事务不隔离导致的问题

以上介绍完事务的四大特性(简称ACID),现在重点来说明下事务的隔离性,

当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,

在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种问题:

更新丢失(Lost update)脏读(Dirty Reads)不可重复读(Non-repeatable Reads)

1、更新丢失(Lost update)

两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。

 

2、脏读(Dirty Reads)

一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。

  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。

例如:用户A向用户B转账1000元,对应SQL命令如下:

--用户A向用户B转账1000元,B的钱增加
update account set money=money+1000 where name='B';
--此时A通知B我给你转钱了,A的钱减少
update account set money=money - 1000 where name='A';

当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),

而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

 

3、不可重复读(Non-repeatable Reads

不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

(1) 读:事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。

(2) 幻读:事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的SQL语句相同)

这是因为在两次查询过程中有另外一个事务插入数据造成的。


 

事务的隔离级别

为了避免上面出现的几种情况,在标准SQL规范中,定义了4+2个事务隔离级别,不同的隔离级别对事务的处理不同

1、未提交读取(相当于with(nolock)):第一级别

  也称为未授权读取:允许脏读取,但不允许更新丢失。

如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。

  该隔离级别可以通过“排他写锁”实现。

  缺点:会产生脏读、不可重复读、幻读。

  案例解读:以前交易所炒股的时候,股民老王购买了5000股,操作员操作录入(此时开启事务),操作时手误,多输入了一个0,数据保存但是未提交。

此时老王查询自己的持股信息,发现自己居然有50000股,瞬间血压升高,昏倒在地。

然后操作员发现自己录入错误,修改成正确的信息,录入完成(事务结束)。

老王被救醒后,哆嗦这查询自己的持股,发现只有5000,没有增减,他之前看到的就是脏读数据。

  解决方案:采用更高级的隔离机制,如提交读。

 

2、提交读取(Oracle和SQLServer默认的):第二级别

  这是大多数数据库系统的默认隔离级别(Oracle和SQLServer默认的)。

  也称为授权读取:允许不可重复读取,但不允许脏读取。

这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

  缺点:会产生不可重复读、幻读。

  案例解读:股市升高后,老王查看自己持有5000股,就想卖掉4000股,在老王卖股票的时候,老王的老婆看股市太高,就登录老王的账号,卖掉3000股。

当老王想卖股票时,发现自己只有2000股,不是之前看到的5000股,这就是不可重复读问题。

  解决方案:采用更高级的隔离机制,如可重复读。

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
存储
SQLServer存储过程中事务的创建
SQLServer存储过程中事务的创建
66 0
|
4月前
|
SQL 数据库 数据安全/隐私保护
SQL Server数据库Owner导致事务复制log reader job无法启动的解决办法
【8月更文挑战第14天】解决SQL Server事务复制Log Reader作业因数据库所有者问题无法启动的方法:首先验证数据库所有者是否有效并具足够权限;若非,使用`ALTER AUTHORIZATION`更改为有效登录名。其次,确认Log Reader使用的登录名拥有读取事务日志所需的角色权限。还需检查复制配置是否准确无误,并验证Log Reader代理的连接信息及参数。重启SQL Server Agent服务或手动启动Log Reader作业亦可能解决问题。最后,审查SQL Server错误日志及Windows事件查看器以获取更多线索。
|
3月前
|
SQL 存储 监控
SQLServer事务复制延迟优化之并行(多线程)复制
【9月更文挑战第12天】在SQL Server中,事务复制延迟会影响数据同步性。并行复制可通过多线程处理优化这一问题,提高复制效率。主要优化方法包括:配置分发代理参数、优化网络带宽、调整系统资源、优化数据库设计及定期监控维护。合理实施这些措施可提升数据同步的及时性和可靠性。
|
3月前
|
SQL 安全 数据库
基于SQL Server事务日志的数据库恢复技术及实战代码详解
基于事务日志的数据库恢复技术是SQL Server中一个非常强大的功能,它能够帮助数据库管理员在数据丢失或损坏的情况下,有效地恢复数据。通过定期备份数据库和事务日志,并在需要时按照正确的步骤恢复,可以最大限度地减少数据丢失的风险。需要注意的是,恢复数据是一个需要谨慎操作的过程,建议在执行恢复操作之前,详细了解相关的操作步骤和注意事项,以确保数据的安全和完整。
153 0
|
4月前
|
SQL 监控 供应链
|
4月前
|
SQL 数据库连接 网络安全
SQLServer非默认端口下事务复制代理作业服务无法启动的处理
【8月更文挑战第14天】若SQL Server非默认端口下的事务复制代理作业无法启动,可按以下步骤解决:1) 确认服务器连接字符串正确无误,包括非默认端口号;2) 检查防火墙设置,确保允许非默认端口的连接;3) 核实SQL Server配置已启用非默认端口;4) 查阅代理作业日志寻找错误详情;5) 重启SQL Server与Agent服务;6) 使用工具测试非默认端口的连接性。如问题持续,请寻求专业支持。
|
4月前
|
SQL 关系型数据库 MySQL
SQL Server 事务执行、回滚
SQL Server 事务执行、回滚
50 0
|
3月前
|
SQL 数据库
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
SQL Server附加数据库出现错误823,附加数据库失败。数据库没有备份,无法通过备份恢复数据库。 SQL Server数据库出现823错误的可能原因有:数据库物理页面损坏、数据库物理页面校验值损坏导致无法识别该页面、断电或者文件系统问题导致页面丢失。
104 12
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
|
22天前
|
SQL 存储 Linux
从配置源到数据库初始化一步步教你在CentOS 7.9上安装SQL Server 2019
【11月更文挑战第16天】本文介绍了在 CentOS 7.9 上安装 SQL Server 2019 的详细步骤,包括配置系统源、安装 SQL Server 2019 软件包以及数据库初始化,确保 SQL Server 正常运行。
|
1月前
|
SQL 存储 Linux
从配置源到数据库初始化一步步教你在CentOS 7.9上安装SQL Server 2019
【11月更文挑战第8天】本文介绍了在 CentOS 7.9 上安装 SQL Server 2019 的详细步骤,包括系统准备、配置安装源、安装 SQL Server 软件包、运行安装程序、初始化数据库以及配置远程连接。通过这些步骤,您可以顺利地在 CentOS 系统上部署和使用 SQL Server 2019。