当我执行select / Insert查询时,SQL Server是否会自动创建一个隐式事务,从而将其视为一个原子操作?
如果某个值尚未存在,请使用以下查询将值插入表中:
INSERT INTO Table1 (FieldA)
SELECT 'newvalue'
WHERE NOT EXISTS (Select * FROM Table1 where FieldA='newvalue')
在WHERE子句的评估和INSERT子句的执行之间,如果没有明确地包装在事务中,是否有可能由另一个用户将'newvalue'插入到表中?
答案 0 :(得分:4)
您在交易和锁定之间感到困惑。如果有任何错误,事务会将您的数据恢复为原始状态。如果不是,它会将数据移动到新状态。在操作交易时,您永远不会将数据置于间歇状态。另一方面,锁定是允许或阻止多个用户同时访问数据的锁定。要回答你的问题,请选择... insert is atomic,只要没有显式请求粒度锁,当select..insert正在进行时,其他用户就无法插入。
答案 1 :(得分:3)
John,答案取决于您当前的隔离级别。如果您设置为READ UNCOMMITTED,您可能正在寻找麻烦,但是如果隔离级别较高,则不应在select和insert之间的表中获得其他记录。使用READ COMMITTED(默认值),REPEATABLE READ或SERIALIZABLE隔离级别,您应该受到保护。
答案 2 :(得分:3)
一个非常常见的问题。在这里解释:
答案 3 :(得分:0)
使用 SSMS 2016 ,可以验证Select/Insert
语句是否请求锁定(因此最有可能以原子方式运行):
为以下事务打开一个新的查询/连接,并在启动调试器之前在ROLLBACK TRANSACTION
上设置一个断点:
BEGIN TRANSACTION
INSERT INTO Table1 (FieldA) VALUES ('newvalue');
ROLLBACK TRANSACTION --[break-point]
在上述断点处,从单独的查询窗口执行以下操作以显示任何锁定(可能需要几秒钟才能注册任何输出):
SELECT * FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID()
AND resource_associated_entity_id = OBJECT_ID(N'dbo.Table1');
上面的BEGIN TRANSACTION
/ INSERT
应该有一个锁(因为默认情况下会在ISOLATION LEVEL
READ COMMITTED
中运行
OBJECT ** ********** * IX LOCK GRANT 1
从 SSMS 的另一个实例中,打开一个新查询并运行以下内容(在上述断点处仍然停止):
INSERT INTO Table1 (FieldA)
SELECT 'newvalue'
WHERE NOT EXISTS (Select * FROM Table1 where FieldA='newvalue')
这应该在查询窗口的标签标题中显示字符串“(正在执行)...”(因为@@LOCK_TIMEOUT
默认为-1)。
从第2步
重新运行查询现在应该显示与Select/Insert
对应的另一个锁:
OBJECT ** ********** 0 IX LOCK GRANT 1
OBJECT ** ********** 0 IX LOCK GRANT 1