[英]Same data is inserted during insert
I have couple insert queries which are merged in transaction. 我有几个插入查询在事务中合并。 First of that insert is to create new product articel number incrementing the most higher in table by one.
首先,要创建新产品的产品编号,将表中最高的编号递增1。 Unfortunetly i just noticed that
mostly
during tests if for instance two users from two diffrent applications click button which trigger my transaction's method they could get same new product number. 偏偏我只注意到
mostly
在测试过程中,如果例如来自两个不同势应用两个用户点击按钮,这触发我的交易的方法,他们可以得到相同的新产品数量。 How can avoid that situation? 如何避免这种情况? Is there something like lock on first insertion so that if first user accessing table to insert restrict other's user/s about their insertion so they have to wait in queue after first user insert is finished?
是否有诸如首次插入锁定之类的东西,以便如果第一个用户访问要插入的表限制其他用户的插入,以便他们在第一个用户插入完成后必须在队列中等待? Is there something like that?
有那样的东西吗? Besides i thought if someone inserts other users are not able to insert.
此外,我认为如果有人插入,其他用户将无法插入。 I made comments in code you to understand.
我在代码中添加了注释,您可以理解。
Part of my transaction query below: 我的部分交易查询如下:
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
For Each kvp As KeyValuePair(Of Integer, Artikel) In artikel.collection
articleIndex = kvp.Key
Dim art As Artikel = kvp.Value
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
Just about the only way to assure that users are not assigned the same values is to issue them from the server when the row is inserted. 确保没有为用户分配相同值的唯一方法就是在插入行时从服务器发出这些值。 It is the entire premise behind the server issuing AI values for PKs.
这是服务器为PK发布AI值的全部前提。
BUT since your thing is a multi-segment, "numeric string" that presents a problem. 但是由于您的问题是一个多段的“数字字符串”,因此会出现问题。 Rather than tearing the string apart to find the Max()+1 for one segment with a WHERE clause on parts of the string.
而不是将字符串拆开,以便在部分字符串上带有WHERE子句的情况下找到一个段的Max()+ 1。 Consider something like this:
考虑这样的事情:
Start with a table used to increment and issue the values: 从用于递增和发布值的表开始:
{DocId Int, SegmentB int, SegmentC Int}
This will simply track the values to use in the other table. 这将仅跟踪要在其他表中使用的值。 Then a stored procedure to create/increment a new code (MySQL - this is a conceptual answer):
然后是一个存储过程,用于创建/增加新代码(MySQL-这是一个概念性的答案):
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetNextProductCode`(in docId int,
in Minr int,
in Rev int
)
BEGIN
SET @maxR = 0;
SET @retCode ='';
if Minr =-1 then
Start transaction;
SET @maxR = (SELECT Max(SegmentB) FROM articlecode WHERE MainId = docId) + 1;
UPDATE articlecode SET SegmentB = @maxR WHERE MainId = docId;
Commit;
Select concat(Cast(docId As char) , '.',
Cast(@maxR AS char) , '.',
Cast(Rev As char)
);
end if;
END
This is a rough idea of the process. 这是一个粗略的想法。 As such, it only works on the second segment (I dunno what happens when you create a NEW SegmentB - does SegmentC reset to 1???).
这样,它仅在第二个段上起作用(我不知道在创建新的SegmentB时会发生什么-SegmentC重置为1 ???)。 The idea is:
这个想法是:
There is much To Do: 有很多事情要做:
1000
and 1
(?) defaults 1
1000
和1
(?)的新行 To get a new code before you insert a row: 要在插入行之前获取新代码:
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("docId", MySqlDbType.Int32).Value = 3
cmd.Parameters.Add("Minr", MySqlDbType.Int32).Value = -1
cmd.Parameters.Add("Rev", MySqlDbType.Int32).Value = 1
dbcon.Open()
Using rdr = cmd.ExecuteReader()
rdr.Read()
Console.WriteLine(rdr(0))
End Using
The obvious downside is that each insert requires you to hit the DB in order to...well save to the DB. 明显的缺点是,每次插入都需要您击中数据库才能将其保存到数据库。 If they were int values it could be a Trigger.
如果它们是整数值,则可能是触发器。
I'm a SQL developer and my VB skills are about fifteen years out of date, but instead of creating the incremented number yourself in VB just let SQL generate them with an IDENTITY field. 我是一名SQL开发人员,我的VB技能已经过时了十五年,但是与其自己在VB中创建递增的数字,不如让SQL使用IDENTITY字段生成它们。 SQL will never allow duplicates and then you just need to return the SCOPE_IDENTITY():
SQL将永远不允许重复,然后您只需要返回SCOPE_IDENTITY():
ALTER TABLE dbo.tbArtikel
ADD [ArtikelID] INT IDENTITY(1,1) PRIMARY KEY;
I have two suggestions: 我有两个建议:
First suggestion : move your code to a stored procedure this way all your users will execute the same transaction where you can set your isolation level the way you want. 第一个建议 :以这种方式将您的代码移动到存储过程中,所有用户将执行同一事务,您可以在其中以所需方式设置隔离级别。 Read This .
阅读此 。
Second suggestion: I would create a unique index on your field Nummer. 第二个建议:我将在您的字段Nummer上创建一个唯一索引。 This way when I try to insert a duplicate value it will raise an error that I can deal with it by telling the user that he need to retry the same operation or retry it automatically.
这样,当我尝试插入重复的值时,将提示用户需要重试相同的操作或自动重试此操作,这将引发错误,我可以对其进行处理。
Trying to lock the record or the table for your operation is not advisable, however you can check this article on code project you might find what you are looking for. 建议不要尝试为操作锁定记录或表,但是您可以在代码项目中查看此文章 ,以查找所需的内容。 Make sure that you provide a mechanism of releasing all locks if your program stops at the middle of the transaction.
如果程序在事务中间停止,请确保提供一种释放所有锁的机制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.