围绕单个语句的事务有什么作用?


71

我了解交易对于协调一对更新可能会很有用。我不了解的是将单个语句包装在事务中,这是我见过的90%。实际上,在现实生活中,以我的经验,找到一系列逻辑相关的事务(每个事务都包装在自己的事务中)是很常见的,但是整个事务并没有包装。

在MS-SQL中,在事务中包装单选,单更新,单插入或单删除有什么好处?

我怀疑这是迷信编程。

Answers:


68

它什么也没做。无论您是否明确地说,所有单独的SQL语句(极少数例外,如无日志的大容量插入或截断表)都自动“在事务中”。(即使它们插入,更新或删除了数百万行) 。

编辑:基于@Phillip在下面的评论...在当前版本的SQL Server中,即使批量插入和截断表也确实将一些数据写入事务日志,尽管不如其他操作那么多。从事务的角度来看,关键的区别是,在其他类型的操作中,正在修改的数据库表中的数据不在允许回滚的状态的日志中。

这意味着将语句对数据库中数据所做的更改记录到事务日志中,以便在操作失败时可以撤​​消它们。

“开始事务”,“提交事务”和“回滚事务”命令提供的唯一功能是允许您将两个或多个单独的SQL语句放入同一事务中。

编辑:(以加强标记注释...)是的,这可能归因于“迷信”编程,或者它可能表明对数据库事务的本质存在根本性的误解。更为慈善的解释是,过度使用一致性是不恰当的结果,而这又是艾默生委婉语的另一个例子:

愚昧的一致性是
小政治家,小政治家,哲学家和神圣人士所崇拜的小妖怪。


4
您应该确定,是的,这是迷信编程。=)
马克·坎拉斯

@ Charles,MySQL呢?
Pacerier 2014年

1
@Pacerier,我不太懂MySQL,但是如果他们的产品在这方面的表现与其他关系产品有所不同,我会感到惊讶。诸如noSQL之类的较新的非关系数据库产品之一可能在不同的范式下运行,但是我敢打赌MySQL是相同的。
查尔斯·布雷塔纳2014年

顺便说一句,在SQL Server中,实际上您可以回滚a TRUNCATE TABLE。在事务中之所以比DELETE在日志记录方面更有效的原因是,仅记录页面取消分配,而不记录行。
布兰登

10

正如查尔斯·布雷塔纳(Charles Bretana)所说,“什么都不做”-除了已经完成的事情之外什么也没有。

是否听说过关系数据库的“ ACID”要求?“ A”代表原子,这意味着该语句可以整体起作用,也可以不起作用,并且在执行该语句时,不能对受该查询影响的数据执行其他任何查询。 BEGIN TRANSACTION / COMMIT将这种锁定功能“扩展”到了由多条语句完成的工作中,但没有为单条语句添加任何内容。

但是,总是在修改数据库(插入,更新,删除)时写入数据库事务日志。这不是一个选择,这会激怒人们。是的,批量插入和恢复模式令人感到困惑,但仍然可以写入。

我也会在这里命名隔离级别。如此混乱将影响单个命令,但这样做仍不会使声明事务包装的查询的执行与“独立”查询的执行有所不同。(请注意,他们是非常强大,并与多语句非常dangeroug宣布的交易。)另请注意,“NOLOCK”并不能适用于插入/更新/删除-那些总是需要的锁的行为。


@Philip,Thx,在研究您的评论时,我发现自从我上次审查此功能(SQL 7或SQL2k)以来,“大容量插入”的情况已发生变化……
Charles Bretana 09年

1
但是,在一个命令中执行两个独立查询而没有代码的显式事务将在数据库中作为两个隐式事务执行,这意味着在隔离级别和脏/写数据方面。
亨里克(Henrik)

4

对我来说,在事务中包装单个语句意味着,如果我在执行手动的一次性UPDATE语句时忘记了WHERE子句,则可以回滚它。它救了我几次。

例如

--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');

SELECT * FROM T1


--------------------------------------------------------------
/* MISTAKE SCENARIO     (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1;   /* open a trans named YOUR_TRANS_NAME_1 */
    UPDATE T1 SET COL2 = NULL;  /* run some update statement */
    SELECT * FROM T1;       /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1;    /* since it did bad things, roll it back */
    SELECT * FROM T1;       /* tans rolled back, data restored. */



--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------

BEGIN TRAN YOUR_TRANS_NAME_2;
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4;   /* run some update statement */
    SELECT * FROM T1;               /* did it correctly this time */

COMMIT TRAN YOUR_TRANS_NAME_2           /* commit (close) the trans */

--------------------------------------------------------------

DROP TABLE T1

--------------------------------------------------------------

5
也许我的问题不清楚。我指的是这样的代码:begin tran; 更新foo set col1 = null; 提交tran; 将其作为一个批次执行。在我维护的多个代码库中,这是一种非常常见的模式,当您跟踪现有应用程序发出的sql时,也很常见。您正在描述一个分两个步骤完成的交互式过程。
MatthewMartin'3

对于在查询处理工具中手动执行的语句,这正确的,因为通过显式启动事务,该工具要求您显式提交(或回滚),而不是自动执行。
查尔斯·布雷塔纳

2

一个可能的借口是,该单个语句可能会导致其他SQL通过触发器运行,并且它们可以防止其中发生不良情况,尽管我希望任何DBMS具有在隐式事务中使用隐式事务的常识。同样的方式。

我能想到的另一件事是,某些API允许您禁用自动提交,并且编写代码是为了防止有人这样做。


1
SQL Server触发器在启动它们的DML代码的隐式事务中运行。是的,MS SQL允许您关闭自动提交。请参阅:msdn.microsoft.com/en-us/library/aa259220(SQL.80).aspx
Shannon Severance 2009年

2

当启动显式事务并发出a时DML,被语句锁定的资源将保持锁定状态,并且直到您手动提交或回滚该语句后,该结果才能从事务外部看到。

这就是您可能需要或不需要的东西。

例如,您可能想向外界显示初步结果,同时又要保持对它们的控制。

在这种情况下,您将启动另一个事务,该事务会在第一个事务提交之前发出锁定请求,从而避免出现竞争情况

DML语句完成或失败之后,立即隐式事务被提交或回滚。


啊,细微的差别。但这并不是显式事务的真正好处,我认为显式事务锁定单语句事务所花费的额外时间显然是个输/掉的情况-较低的性能和较低的并发性,尽管可能是毫秒。
马修·马丁

1
@MatthewMartin:我没有说什么好处或缺点,我只是解释了区别。交易并不全都与绩效有关。对于instace,您可能希望向外界展示初步结果,同时仍然要锁定它们。在这种情况下,您将启动另一个事务,该事务将在第一个事务提交之前发出锁定请求,从而避免争用情况。在这种情况下,您仍然需要将此单个语句包装到事务中。
Quassnoi

SQL Server不支持真正的嵌套事务。开始另一个是一个坏主意。sqlskills.com/BLOGS/PAUL/post/...
IamIC

1

SQL Server具有允许关闭会话的自动提交的设置。对于某些客户端,它甚至是默认设置(请参阅https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-server-2017

根据您使用的框架和/或数据库客户端的不同,不将每个单独的命令放入自己的事务中可能会导致将它们全部集中到一个默认事务中。明确地将它们包装在事务中,可以明确声明其意图,并实际上确保它按照程序员的意图发生,而不管当前的自动提交设置如何,尤其是在没有公司范围的自动提交策略的情况下。

如果的begin tran /提交在数据库中被观察TRAN命令(根据您的评论在这里),那么框架也有可能代表毫无疑问的程序员生成它们。(有多少开发人员密切检查其框架生成的SQL代码?)

我希望这仍然有意义,尽管这个问题有些古老。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.