【发布时间】:2017-05-13 01:48:11
【问题描述】:
我开始开发应处理数据访问并发问题的应用程序,但我无法理解如何正确使用事务隔离级别。
我有一个名为Folders 的表格,其中包含一个树状文件夹结构:
+-----------------------------------------------------------------+
| Id (int) | Name (varchar) | FullPath (varchar) | ParentId (int) |
|----------+----------------+--------------------+----------------|
| 1 | 'root1' | '/root1/' | NULL |
| 2 | 'c1' | '/root1/c1/' | 1 |
| 3 | 'c2' | '/root1/c1/c2/' | 2 |
| 4 | 'root2' | '/root2/' | NULL |
+----------+----------------+--------------------+----------------+
我正在尝试像这样实现“移动文件夹”工作流程(例如,我想将 ID=2 的文件夹移动到 ID=4 的新父级):
- 开始交易
- 读取 ID=2 的文件夹(称为文件夹 2):
SELECT * FROM Folders WHERE Id=2 - 读取 ID=4 的文件夹(称为文件夹 4):
SELECT * FROM Folders WHERE Id=4 - 更新
ParentId和FullPath的folder2:UPDATE Folders SET ParentId=folder4.Id, FullPath=folder4.FullPath+folder2.Name+'/' WHERE Id = folder2.Id - 读取
folder2的所有子文件夹(称它们为subfoldersOfFolder2):SELECT * FROM Folders WHERE FullPath LIKE folder2.FullPath + '%' - 对于
subfoldersOfFolder2中的每个subfolder更新FullPath列(查询省略) - 提交事务
显然,在我的事务完成之前,我不希望任何其他事务写入(甚至读取)folder2 和 subfoldersOfFolder2。
在阅读this article on SQL Server transactions 之后,我了解到在第 1 步将隔离级别设置为 Serializable 将帮助我实现这一目标。但由于某种原因,这似乎没有发生。我尝试让事务保持打开状态(在步骤 #7 之前停止),打开另一个 SSMS 实例并执行SELECT * FROM Folders,查询成功完成,我仍然可以看到第一个事务读取的数据。
为什么会这样?如何防止其他人读/写folder2 和subfoldersOfFolder2?我觉得我错过了关于事务如何实际锁定数据的重要内容。
【问题讨论】:
-
Serializable专门表示全局没有并发。这真的是你想要的吗?如果不是,您可能应该让修改代码首先选择带有updlock, holdlock的所有相关父节点。但是,这只会设置修改代码,它不会阻止人们阅读您要修改的子文件夹的路径,但没有。鉴于您只有在锁定并读取父文件夹(竞争条件)后才知道这些子文件夹的 ID,因此每次编辑路径时,您似乎都希望在整个表上放置一个tablock, xlock, holdlock。
标签: sql sql-server transactions