Detecting dirty reads from a stored procedure(从存储过程中检测脏读)
问题描述
我有 100 个线程,每个线程都调用如下定义的存储过程.
I've got 100 threads that are each calling the stored procedure as defined below.
如何防止脏读?
SET QUOTED_IDENTIFIER OFF
SET ANSI_NULLS OFF
GO
ALTER procedure GetNextCerealIdentity
(@NextKey int output, @TableID int)
AS
declare @RowCount int, @Err int
set nocount on
select
@NextKey = 0
begin transaction
Again:
/*Update CfgCerealNumber Table */
UPDATE CfgCerealNumber
SET CerealNumber = CerealNumber + 1
WHERE CerealNumberID = @TableID
SELECT
@RowCount = @@RowCount,
@Err = @@Error /*Obtain updated Cereal number previously incremented*/
IF @Err <> 0 /* If Error gets here then exit */
BEGIN
RAISERROR ('GetNextCerealIDSeries Failed with Error: %d TableID: %d ', 16, 1, @Err, @TableID)
ROLLBACK TRANSACTION
set nocount off
return 1
END
IF @RowCount = 0 /* No Record then assume table is not */
/* been initialized for TableID Supplied*/
BEGIN
RAISERROR('No Table Record Exists in CfgCerealNumber for ID:%d ', 16, 1, @TableID)
set nocount off
Rollback Transaction
return 1
END
/*Obtain updated Cereal number previously incremented*/
SELECT @NextKey = CerealNumber
FROM CfgCerealNumber
WHERE CerealNumberID = @TableID
SELECT @Err = @@Error /*Obtain updated Cereal number previously incremented*/
IF @Err <> 0 /* If Error gets here then exit */
BEGIN
RAISERROR('GetNextCerealIDSeries Failed with Error: %d TableID: %d ', 16, 1, @Err, @TableID)
Rollback Transaction
set nocount off
return 1
END
commit transaction
set nocount off
return 0
GO
看起来这部分存储过程在并行运行时大约有 0.01% 的时间返回相同的值:
It looks like this part of the stored procedure is returning the same value around 0.01% of the time when run in parallel:
SELECT @NextKey = CerealNumber
FROM CfgCerealNumber
WHERE CerealNumberID = @TableID
我通过将更新包装在事务中来以防止脏读的方式构建我的代码.
I've structured my code in such a way to prevent dirty reads by wrapping the update in a transaction.
如何防止脏读?
推荐答案
如果您需要更新并返回您更新的内容,那么我会使用 OUTPUT 子句:
If you need to update and return what you updated, then I would just use the OUTPUT clause:
UPDATE CfgCerealNumber
SET CerealNumber = CerealNumber + 1
OUTPUT INSERTED.CerealNumber
WHERE CerealNumberID = @TableID;
如果你需要额外的检查,你可以在从存储过程返回结果集之前输出到一个声明的表变量中.
If you need additional checking, you can OUTPUT into a declared table variable before returning the result set from the stored procedure.
另一种选择是先在表上创建一个阻塞锁,然后更新:
Another alternative would be to create a blocking lock on the table first, and then update:
SELECT @CerealNumber = CerealNumber + 1
FROM CfgCerealNumber WITH (HOLDLOCK, UPDLOCK)
WHERE CerealNumberID = @TableID;
UPDATE CfgCerealNumber
SET CerealNumber = @CerealNumber
WHERE CerealNumberID = @TableID;
但我会放下钱,因为我已经看到这仍然会导致问题.我不太相信它.
But I would put money down that I've seen this still cause problems. I trust it much less.
这篇关于从存储过程中检测脏读的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:从存储过程中检测脏读


- 以一个值为轴心,但将一行上的数据按另一行分组? 2022-01-01
- SQL 临时表问题 2022-01-01
- 在SQL中,如何为每个组选择前2行 2021-01-01
- 导入具有可变标题的 Excel 文件 2021-01-01
- 更改自动增量起始编号? 2021-01-01
- 如何使用 pip 安装 Python MySQLdb 模块? 2021-01-01
- 远程 mySQL 连接抛出“无法使用旧的不安全身份验证连接到 MySQL 4.1+"来自 XAMPP 的错误 2022-01-01
- 如何将 SonarQube 6.7 从 MySQL 迁移到 postgresql 2022-01-01
- 如何将 Byte[] 插入 SQL Server VARBINARY 列 2021-01-01
- 使用 Oracle PL/SQL developer 生成测试数据 2021-01-01