【发布时间】:2011-03-07 03:11:32
【问题描述】:
在事务中包含选择语句有什么意义?我认为选择语句只是从数据库中“获取”数据,它们没有机会回滚某些东西,因为您无法更改数据。那么,这是否意味着我们永远不需要在事务中放置 select 语句?我说的对吗?
谢谢。
【问题讨论】:
标签: sql-server-2005 tsql transactions
在事务中包含选择语句有什么意义?我认为选择语句只是从数据库中“获取”数据,它们没有机会回滚某些东西,因为您无法更改数据。那么,这是否意味着我们永远不需要在事务中放置 select 语句?我说的对吗?
谢谢。
【问题讨论】:
标签: sql-server-2005 tsql transactions
您是对的:在标准 isolation level、read committed 中,您不需要在事务中包装 select 语句。无论您是否将它们包装在事务中,都将保护 Select 语句免受脏读。
connection 1: connection 2:
begin transaction
update user set name = 'Bill' where id = 1
select name from users where id = 1
rollback transaction
select 语句不会读取回滚的更新:它们没有包装在事务中并不重要。
如果您需要repeatable reads,那么将选择包装在默认事务中没有帮助:
connection 1: connection 2:
begin transaction
select name from users where id = 1
update user set name = 'Bill' where id = 1
select name from users where id = 1
commit transaction
begin 和 commit 语句在这里不起作用:第二个 select 可能读取旧名称,或者它可能读取新名称.
但是,如果您以更高的隔离级别运行,例如 serializable 或 repeatable read,则该组将受到不可重复读取的保护:
connection 1: connection 2:
set transaction isolation level
repeatable read
begin transaction
select name from users where id = 1
update user set name = 'Bill' where id = 1
select name from users where id = 1 |
commit transaction |
|--> executed here
在这种情况下,update 将阻塞直到第一个事务完成。
很少使用较高的隔离级别,因为它们会降低可以同时在数据库中工作的人数。在最高级别 serializable,报告查询会暂停任何更新活动。
【讨论】:
SET READ_COMMITTED_SNAPSHOT ON 更改此行为。
set read_committed_snapshot on之后,说“更新”将不再阻塞是对的吗?
read_committed_snapshot,读取不会阻止更新,但一个更新仍会阻止另一个更新。为此,SQL Server 必须做更多的磁盘 I/O。
您可能在此交易期间进行其他更新/插入。如果您访问数据库的代码是以可重用的方式编写的,那么您可能不知道选择是否是事务中唯一发生的事情。
您的 select 语句可能希望在事务期间保持一致,并与其他事务中发生的数据更改保持一致。您需要在系统中设置某种isolation level,以防止脏读(读取另一个事务中未提交的更改)或幻读(读取另一个事务中已提交的更改)。
不用说,使用交易会更好地为您服务。
【讨论】:
单个 SELECT 语句一开始是原子的 - 将它包含在事务中是多余的。如果有多个 SELECT 语句,则可以保证在所有语句都完成之前没有人更改任何影响它们的任何东西。
【讨论】:
您可能不会更改数据,但其他一些数据库连接可以。
【讨论】:
没有。
事务为您提供数据库的一致视图。
如果您希望您的选择在重复它们时返回相同的结果,事务可以提供。
【讨论】:
使用带有选择的事务的另一个原因:
在某些时候,您可能希望从参与事务的其他方法中调用您的 select 方法,并且您希望 select 参与当前事务。如果您有一个一致的设计,其中所有数据库操作都在事务中执行,那么任何方法的调用者都知道它将参与他们的事务。
对于少量的前期开发成本,这可以帮助避免一些相当大的变化,以便在需求发生变化或添加新需求时试图强行交易。
【讨论】:
如果您确定正在发生的所有事情都是一个 SELECT,那么它就不需要在事务中。您是否 100% 确定现在和永远只是一个 SELECT?
【讨论】: