mssql

推荐列表 站点导航

当前位置:首页 > 数据库 > mssql >

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套

来源:网络整理  作者:网络  发布时间:2020-12-11 13:19
嵌套事务可不会像其语法表现的那样看起来允许事务嵌套。我真不知道为什么有人会这样写代码,我唯一能够想到的...

复制代码 代码如下:

误区 #26: SQL Server中存在真正的“事务嵌套”
在开始这个测试之前我首先清除了日志,然后运行如下代码:
CREATE TABLE t1 (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'a');
GO
下面我将事务提交后运行CheckPoint(对于简单恢复模式的数据库将会截断日志),得到的结果:
GO



对于嵌套事务来说---Just Say no。(这句话你可以当作来自SQLSkill.com的一个热心的家伙给的福利:-)



COMMIT TRAN OuterTran;


复制代码 代码如下:

复制代码 代码如下:

复制代码 代码如下:


复制代码 代码如下:

复制代码 代码如下:

CREATE DATABASE NestedXactsAreNotReal;
CREATE CLUSTERED INDEX t1c1 ON t1 (c1);
错误

测试 #3:提交嵌套的事务的内部事务至少可以让我清除日志吧。
我们发现日志的使用不减反赠,这是由于日志写入了CheckPoint记录(详情请看:How do checkpoints work and what gets logged)。提交内部事务不会导致日志被清除,这是由于外部事务回滚时也会连同内部事务一起回滚(译者注:所以这部分VLF在外部事务提交之前永远不会被标记位reusable)。所以这部分日志在外部事务提交之前永远不会被截断。为了证明这一点,我提交外部事务,然后再来看日志:
现在我得到结果是0和0。正如Books Online所言,这个回滚操作将外部事务进行了回滚并将全局变量@@TRANCOUNT设置为0。事务中所有的修改都被回滚,如果想部分回滚的话只能使用SAVE TRAN 和ROLLBACK TRAN。

但实际上当回滚内层事务时,会回滚整个事务,而不是仅仅是内层。这也是为什么我说嵌套事务并不存在。
GO
DBCC SQLPERF ('LOGSPACE');


GO 1000

DBCC SQLPERF ('LOGSPACE');

嵌套事务可不会像其语法表现的那样看起来允许事务嵌套。我真不知道为什么有人会这样写代码,我唯一能够想到的就是某个哥们对SQL Server社区嗤之以鼻然后写了这样的代码说:“玩玩你们”。


好吧,由Books Online来看,我只能使用外部事务的名称或是将事务名称留空来进行回滚,代码如下:
BEGIN TRAN OuterTran;
ROLLBACK TRAN InnerTran;
GO 1000
GO
INSERT INTO t1 DEFAULT Values;
BEGIN TRAN InnerTran;
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
GO
让我更详细的解释一下,SQL Server允许你在一个事务中开启嵌套另一个事务,SQL Server允许你提交这个嵌套事务,也允许你回滚这个事务。

GO

COMMIT TRAN InnerTran;
COMMIT TRAN InnerTran;
GO

GO
测试 #1:回滚内部事务时仅仅回滚内部事务?
ROLLBACK TRAN;

ROLLBACK TRAN OuterTran;

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”


SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”


但运行上面查询后结果是0,这说明外部事务的回滚会影响内部事务。
SET NOCOUNT ON;
GO 1000


GO
BEGIN TRAN OuterTran;


GO


复制代码 代码如下:

GO

USE NestedXactsAreNotReal;
DBCC SQLPERF ('LOGSPACE');
无法回滚 InnerTran。找不到该名称的事务或保存点。
么样,日志使用百分比大幅下降了吧。

GO

GO
测试 #2:嵌套事务中内部事务提交后会保存内部事务的修改吗?

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”

ALTER DATABASE NestedXactsAreNotReal SET RECOVERY SIMPLE;
GO
所以作为开发人员来讲,永远不要对事务进行嵌套。事务嵌套是邪恶的。


GO
正如我所期待,得到的结果是1000。这说明内部事务提交是会修改到磁盘的。但是如果这时外部事务回滚的话,那么不应该回滚内部事务…
CHECKPOINT;
GO


GO
INSERT INTO t1 DEFAULT Values;
GO
CHECKPOINT;
BEGIN TRAN InnerTran;
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
SELECT COUNT (*) FROM t1;
如果你不相信我说的,那么通过下面的例子就就会相信。创建完数据库和表之后,每一条记录都会导致日志增加8K。


SELECT COUNT (*) FROM t1;


GO

INSERT INTO t1 DEFAULT Values;
GO 1000
GO
GO
GO
GO

复制代码 代码如下:

BEGIN TRAN OuterTran;
GO
INSERT INTO t1 DEFAULT Values;

复制代码 代码如下:

你可以看到得出的结果是2和2000,下面我来回滚内部的事务,按照我们的猜想应该只回滚1000条吧,但事实上你会得到如下结果:

GO
GO
但是,嵌套事务并不是真正的“嵌套”,对于嵌套事务来说SQL Server仅仅能够识别外层的事务。嵌套事务是日志不正常增长的罪魁祸首之一因为开发人员以为回滚了内层事务,仅仅是回滚内层事务。
消息 6401,级别 16,状态 1,第 2 行

BEGIN TRAN InnerTran;
得到结果:

复制代码 代码如下:

相关热词:

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!

本文地址: https://www.juheyunku.com/sql/mssql/2563.shtml

最新文章
sql server 关于设置null的一 sql server 关于设置null的一

时间:2020-12-28

详解SQL游标的用法 详解SQL游标的用法

时间:2020-12-27

vs code连接sql server数据库步 vs code连接sql server数据库步

时间:2020-12-27

图书管理系统的sqlserver数 图书管理系统的sqlserver数

时间:2020-12-25

详解SQL 通配符 详解SQL 通配符

时间:2020-12-25

sql四大排名函数之ROW_NUM sql四大排名函数之ROW_NUM

时间:2020-12-25

SQLServer数据库处于恢复挂 SQLServer数据库处于恢复挂

时间:2020-12-24

Win10 64位安装个人版SQL20 Win10 64位安装个人版SQL20

时间:2020-12-24

Copyright © www.juheyunku.com      关于 | 合作 | 声明 | 联系 | 更新 | 地图 | Tags

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套

2020-12-11 编辑:网络

复制代码 代码如下:

误区 #26: SQL Server中存在真正的“事务嵌套”
在开始这个测试之前我首先清除了日志,然后运行如下代码:
CREATE TABLE t1 (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'a');
GO
下面我将事务提交后运行CheckPoint(对于简单恢复模式的数据库将会截断日志),得到的结果:
GO



对于嵌套事务来说---Just Say no。(这句话你可以当作来自SQLSkill.com的一个热心的家伙给的福利:-)



COMMIT TRAN OuterTran;


复制代码 代码如下:

复制代码 代码如下:

复制代码 代码如下:


复制代码 代码如下:

复制代码 代码如下:

CREATE DATABASE NestedXactsAreNotReal;
CREATE CLUSTERED INDEX t1c1 ON t1 (c1);
错误

测试 #3:提交嵌套的事务的内部事务至少可以让我清除日志吧。
我们发现日志的使用不减反赠,这是由于日志写入了CheckPoint记录(详情请看:How do checkpoints work and what gets logged)。提交内部事务不会导致日志被清除,这是由于外部事务回滚时也会连同内部事务一起回滚(译者注:所以这部分VLF在外部事务提交之前永远不会被标记位reusable)。所以这部分日志在外部事务提交之前永远不会被截断。为了证明这一点,我提交外部事务,然后再来看日志:
现在我得到结果是0和0。正如Books Online所言,这个回滚操作将外部事务进行了回滚并将全局变量@@TRANCOUNT设置为0。事务中所有的修改都被回滚,如果想部分回滚的话只能使用SAVE TRAN 和ROLLBACK TRAN。

但实际上当回滚内层事务时,会回滚整个事务,而不是仅仅是内层。这也是为什么我说嵌套事务并不存在。
GO
DBCC SQLPERF ('LOGSPACE');


GO 1000

DBCC SQLPERF ('LOGSPACE');

嵌套事务可不会像其语法表现的那样看起来允许事务嵌套。我真不知道为什么有人会这样写代码,我唯一能够想到的就是某个哥们对SQL Server社区嗤之以鼻然后写了这样的代码说:“玩玩你们”。


好吧,由Books Online来看,我只能使用外部事务的名称或是将事务名称留空来进行回滚,代码如下:
BEGIN TRAN OuterTran;
ROLLBACK TRAN InnerTran;
GO 1000
GO
INSERT INTO t1 DEFAULT Values;
BEGIN TRAN InnerTran;
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
GO
让我更详细的解释一下,SQL Server允许你在一个事务中开启嵌套另一个事务,SQL Server允许你提交这个嵌套事务,也允许你回滚这个事务。

GO

COMMIT TRAN InnerTran;
COMMIT TRAN InnerTran;
GO

GO
测试 #1:回滚内部事务时仅仅回滚内部事务?
ROLLBACK TRAN;

ROLLBACK TRAN OuterTran;

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”


SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”


但运行上面查询后结果是0,这说明外部事务的回滚会影响内部事务。
SET NOCOUNT ON;
GO 1000


GO
BEGIN TRAN OuterTran;


GO


复制代码 代码如下:

GO

USE NestedXactsAreNotReal;
DBCC SQLPERF ('LOGSPACE');
无法回滚 InnerTran。找不到该名称的事务或保存点。
么样,日志使用百分比大幅下降了吧。

GO

GO
测试 #2:嵌套事务中内部事务提交后会保存内部事务的修改吗?

SQL Server误区30日谈 第26天 SQL Server中存在真正的“事务嵌套”

ALTER DATABASE NestedXactsAreNotReal SET RECOVERY SIMPLE;
GO
所以作为开发人员来讲,永远不要对事务进行嵌套。事务嵌套是邪恶的。


GO
正如我所期待,得到的结果是1000。这说明内部事务提交是会修改到磁盘的。但是如果这时外部事务回滚的话,那么不应该回滚内部事务…
CHECKPOINT;
GO


GO
INSERT INTO t1 DEFAULT Values;
GO
CHECKPOINT;
BEGIN TRAN InnerTran;
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
SELECT COUNT (*) FROM t1;
如果你不相信我说的,那么通过下面的例子就就会相信。创建完数据库和表之后,每一条记录都会导致日志增加8K。


SELECT COUNT (*) FROM t1;


GO

INSERT INTO t1 DEFAULT Values;
GO 1000
GO
GO
GO
GO

复制代码 代码如下:

BEGIN TRAN OuterTran;
GO
INSERT INTO t1 DEFAULT Values;

复制代码 代码如下:

你可以看到得出的结果是2和2000,下面我来回滚内部的事务,按照我们的猜想应该只回滚1000条吧,但事实上你会得到如下结果:

GO
GO
但是,嵌套事务并不是真正的“嵌套”,对于嵌套事务来说SQL Server仅仅能够识别外层的事务。嵌套事务是日志不正常增长的罪魁祸首之一因为开发人员以为回滚了内层事务,仅仅是回滚内层事务。
消息 6401,级别 16,状态 1,第 2 行

BEGIN TRAN InnerTran;
得到结果:

复制代码 代码如下:

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供学习参考!
本文地址为 https://www.juheyunku.com/sql/mssql/2563.shtml

相关文章

风云图片

推荐阅读

返回mssql频道首页