【发布时间】:2025-12-26 05:50:16
【问题描述】:
我有几个插入查询合并到事务范围中。插入的第一个是创建新的产品货号,该货号是通过将表中的最高值加一来构建的。不幸的是,我只是注意到,主要是在测试期间,例如,如果来自两个不同应用程序的两个用户单击触发我的交易方法的按钮,他们可以获得相同的新产品编号并插入它。我怎样才能避免这种情况?
我的部分交易查询如下:
Public Sub ProcessArticle(ByRef artikel As ArticlesVariations)
Dim strcon = New AppSettingsReader().GetValue("ConnectionString", GetType(System.String)).ToString()
Using connection As New SqlConnection(strcon)
connection.Open()
Using transaction = connection.BeginTransaction()
Try
Using cmd As New SqlCommand("INSERT INTO tbArtikel (Nummer) VALUES (@Nummer);Select Scope_Identity()", transaction.Connection)
cmd.CommandType = CommandType.Text
cmd.Connection = connection
cmd.Transaction = transaction
'Get next product number from table tbArtikel (this will be new product number)'
Dim NewArtNummer as String = New DALArtikel().GetNewArtikelNumber(transaction)
art.Nummer = NewArtNummer
cmd.Parameters.AddWithValue("@Nummer", art.Nummer)
'Get inserted product id for other diffrent inserts below'
newArticleRowId = CInt(cmd.ExecuteScalar())
'....
other INSERTs queries to other tables ...
...'
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
Throw 'Rethrow exception.'
End Try
End Using
End Using
End Sub
文章编号是varchar 列(我知道这很糟糕等),但这是它在当前范围内的实现方式,不可能更改它。
请注意,我不能在数据库级别进行任何更改,例如新表、触发器等(一个例外是在数字列上创建唯一索引)。我必须从应用程序级别实现。
我想到了三个选项,想听听您的建议:
第一个选项:
a) 将此列设为唯一列,这样当几个用户仅插入一个时,将插入该数字,但所有其余用户都会从捕获有关唯一键违规的错误中得到错误,因此我可以以某种方式管理它使信息重试。
b) 与 a) 相同,但隔离级别设置为 ReadUncommited - 从我的角度来看,这将让我知道,当下一个用户读取 newnumber 时,他们有机会从脏数字中读取(所以也来自第一个用户插入),因此他们有机会获得下一个数字。
第二个选项:
只是为了使事务隔离以读取未提交 - 但这并不能保证所有同一行用户都会获得新号码(可能是最糟糕的)
第三个选项:
听说过TABLOCK,但不知道在这种情况下是否可以考虑。
...还有别的吗?
目前我正在考虑使用第一个选项 -catch 错误并通知用户。
【问题讨论】:
-
SQL Server 的哪个版本?
-
@Shnugo 不知道,但肯定不少于 2008 年
-
从 SQL Server 2012 开始有
SEQUENCE,但这在这里对您没有帮助。显然其他人也有同样的问题,因此发明了这个...... -
@Shnugo 如果这对我的选择没有帮助呢?
标签: sql-server vb.net tsql