简体   繁体   English

插入过程中插入了相同的数据

[英]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: 这个想法是:

  • pass numbers so there is no need to tear up a string 通过数字,因此无需撕裂字符串
  • pass -1 for the segment you need the next value for 为该段传递-1,您需要下一个值
  • the sp gets the Max()+1 and updates the counter table so the next user will get a new value sp获得Max()+ 1并更新计数器表,以便下一个用户将获得新值
  • If for some reason you end up not saving the row, there will be gaps 如果由于某种原因您最终没有保存该行,则将存在间隙
  • the sp uses a transaction (probably only needs to protect the update) so that only 1 update can happen at a time sp使用一个事务(可能只需要保护更新),因此一次只能进行1个更新
  • returns the new code. 返回新代码。 it could just return 2 values, but your going to glue them together anyway 它可能只返回2个值,但是无论如何您都要将它们粘合在一起

There is much To Do: 有很多事情要做:

  • It only does SegmentB 仅细分B
  • For a NEW DocId (-1), insert a new row with 1000 and 1 (?) defaults 对于新的DocId(-1),请插入默认1 10001 (?)的新行
  • Same for a NEW segmentB (whatever it is): insert a new row for that DocId with default values 与NEW segmentB相同(无论它是什么):为该DocId插入一个具有默认值的新行

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.

相关问题 将数据插入 sql 表并获取最近插入的 iD 并将数据从不同表插入到同一表中 - insert data into sql table and get recent inserted iD and insert data in same table from different table 在批量插入期间获取有关插入行的信息 - Get Information about Inserted Rows during a BULK INSERT “在不存在的地方插入”是否包括在同一插入处插入的记录 - does 'insert where not exists' include records which inserted at the same insert 在触发器中插入期间更新数据,然后插入 - Update data during insert in a Trigger and then insert 如何在没有创建或插入或cte的情况下生成与插入的行号相同的行号 - How to Generate row number as same as inserted without create or insert or cte 将数据插入到SQL Server中的另一个表中时,将数据插入表中 - Insert data into a table when the data is inserted into another table in SQL Server 添加插入记录的数据和时间信息。 不要使用插入声明 - Adding data & time info of the record inserted. NOT BY USING INSERT STATEMENT ROLLBACK 使 INSERTED 表中的数据在 AFTER INSERT TRIGGER 中删除 - ROLLBACK make data in INSERTED table is removed in AFTER INSERT TRIGGER INSERT存储过程可以工作,但从方法调用时未插入数据吗? - INSERT Stored Procedure works but data is not inserted when called from method? 触发插入表中的数据保留以及一列上的更新和插入组合 - Triggers data retention in inserted table and combination of update and insert on one column
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM