在使用UNION时,SQL查询是否保证以原子方式执行?

Gil*_*ili 8 sql transactions

我发出一个单独的SQL查询,包含使用UNION分组的多个SELECT:

SELECT *
FROM   employee 
       LEFT JOIN department 
          ON employee.DepartmentID = department.DepartmentID
UNION
SELECT *
FROM   employee
       RIGHT JOIN department
          ON employee.DepartmentID = department.DepartmentID;
Run Code Online (Sandbox Code Playgroud)

假设我在READ_COMMITTED事务隔离下执行此查询,两个SELECT语句是否保证以原子方式执行?或者我是否存在各个SELECT语句之间数据更改的风险?SQL规范是否讨论过这种事情?

澄清:当我说"原子"时,我不是指ACID中的"A".我的意思是我希望在查询完成之前对department和employee表进行读锁定.

Mar*_*ith 4

是的,该语句是原子的,但数据可以在两次读取之间发生变化。

Read Committed只保证您不会读取脏数据,它对读取的一致性没有任何保证,因为您需要更高的隔离级别。

正如您所说,您会接受 SQL Server 示例...

连接1

(假设在悲观的已提交读隔离级别下)

CREATE TABLE employee
(
name VARCHAR(50),
DepartmentID INT
)

CREATE TABLE department
(
DepartmentID INT
)

INSERT INTO department VALUES (1)
INSERT INTO employee VALUES ('bob',1)

declare @employee TABLE
(
name VARCHAR(50),
DepartmentID INT
)


WHILE ((SELECT COUNT(*) FROM @employee) < 2)
BEGIN
DELETE FROM  @employee

INSERT INTO @employee
SELECT employee.*
FROM   employee 
       LEFT JOIN department 
          ON employee.DepartmentID = department.DepartmentID
UNION
SELECT employee.*
FROM   employee
       RIGHT JOIN department
          ON employee.DepartmentID = department.DepartmentID

END;          

SELECT * FROM @employee
Run Code Online (Sandbox Code Playgroud)

连接2

while (1=1)
UPDATE employee SET name = CASE WHEN name = 'bob' THEN 'bill' else 'bob' END
Run Code Online (Sandbox Code Playgroud)

现在返回连接 1

name                                               DepartmentID
-------------------------------------------------- ------------
bill                                               1
bob                                                1
Run Code Online (Sandbox Code Playgroud)

(记得切换回连接 2 来杀死它!)

READ COMMITED涵盖此行为的具体文档在这里

共享锁的类型决定了何时释放它。在处理下一行之前释放行锁。当读取下一页时,页锁被释放,当语句完成时,表锁被释放。