单个语句的交易是做什么的?
我了解一个事务如何协调一对更新。 我不明白的是在交易中包装单一的陈述,这是我所见过的90%。 实际上,在现实生活中,根据我的经验,find一系列逻辑上相关的交易,每个交易都包含在自己的交易中,但是整个交易并没有包含在交易中。
在MS-SQL中,在事务中包装单选,单更新,单插入或单删除有什么好处?
我怀疑这是迷信的编程。
它什么都不做。 所有单独的SQL语句(极less数情况下,例如大容量插入无日志或截断表)都是自动的“在事务中”,无论您是否明确地说出来(即使它们插入,更新或删除数百万行) 。
编辑:基于@ Phillip的评论下面…在当前版本的SQL Server中,即使大容量插入和截断表也写入一些数据到事务日志,虽然没有其他操作那么多。 从事务angular度来看,关键的区别在于,在这些其他types的操作中,被修改的数据库表中的数据不会处于允许回退状态的日志中。
所有这一切意味着语句对数据库中的数据进行的更改将logging到事务日志中,以便在操作失败时可以撤消它们。
“Begin Transaction”,“Commit Transaction”和“Rollback Transaction”命令提供的唯一function是允许您将两个或多个单独的SQL语句放入同一个事务中。
编辑:(加强标记评论…)是的,这可能是由于“迷信”编程,也可能是数据库交易性质的根本误解。 更为慈善的解释是,这只是过度应用一致性的结果,这是不恰当的,而爱默生委婉语的另一个例子是:
愚蠢的一致性是小心灵的大地精,
受到小政治家,哲学家和神学家的喜爱
正如查尔斯·布雷塔那(Charles Bretana)所说,“它什么都不做” – 除了已经完成的事情之外,什么也没有。
有没有听说过关系数据库的“ACID”要求? “A”代表Atomic,意味着声明可以全部工作,也可以不工作,并且在执行声明的同时, 不会 对受该查询影响的数据进行其他查询。 BEGIN TRANSACTION / COMMIT将这个lockingfunction“扩展”到多个语句所做的工作中,但是它并没有增加单个语句。
但是,数据库事务日志总是写入到数据库被修改(插入,更新,删除)的时候。 这不是一个select,这是一个往往会激怒人的事实。 是的,有批量插入和恢复模式,但它仍然被写入的Wierdness。
我也会在这里说出隔离级别。 这样做会影响个别命令,但是这样做仍然不会使“声明事务包装”查询的执行与“独立”查询有所不同。 (请注意,对于多语句声明的事务,它们可能非常强大而且非常危险。)另请注意,“nolock”不适用于插入/更新/删除 – 这些操作始终需要locking。
对于我来说,在一个事务中包装单个语句意味着如果我在执行一次手动的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 --------------------------------------------------------------
一个可能的借口是,这个单一的语句可能会导致一堆其他的SQL通过触发器运行,并且他们正在防止在那里坏事,虽然我希望任何DBMS有常识使用隐式事务同样的方式已经。
我能想到的另一件事是,有些API允许你禁用自动提交,而代码的编写只是为了防止有人这样做。
当您启动显式事务并发出DML
,由语句locking的资源将保持locking状态,并且直到您手动提交或回滚事件才会从事务外部看到语句的结果。
这是你可能或不需要的。
例如,您可能想要向外界显示初步结果,同时仍然locking它们。
在这种情况下,您启动另一个事务,在第一个事务提交之前发出locking请求,从而避免竞争状况
隐式事务在DML
语句完成或失败后立即被提交或回滚。