【问题标题】:Auto increment isn't correct when running two instances运行两个实例时自动增量不正确
【发布时间】:2020-01-26 17:46:27
【问题描述】:

我正在运行以下代码的 2 个实例,它们连接到 System.Data.SQLite 数据库。当我使用任何一个实例向数据库中插入一行时,从其他实例读取时自动递增的值 (ID) 不正确。这背后的原因是什么?

Imports System.Data.SQLite
Public Class Form1
    Public cnn As SQLiteConnection
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        cnn = New SQLiteConnection("Data Source=\\abc\xx\x_backup.db;Password=password;Connect Timeout=55;FailIfMissing=True")
        cnn.ParseViaFramework = True
        cnn.Open()
    End Sub
    Public Function inserttoTable(ByVal sql As String) As DataTable

         Try
            sql = "SELECT max(ID) FROM joblog;"
            Dim mycommand As SQLiteCommand = New SQLiteCommand(cnn)
            mycommand.CommandText = sql
            MsgBox(mycommand.ExecuteScalar)
            sql = "INSERT INTO joblog (jobid) VALUES (123);"

            mycommand = New SQLiteCommand(cnn)
            mycommand.CommandText = sql
            MsgBox(mycommand.ExecuteNonQuery())
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try

【问题讨论】:

  • 首先,你的sql语句应该被做成存储过程(总是)。其次,在一个 INSERT 函数中有两条 SQL 语句。你到底想做什么?
  • @ciammarino should be made into stored procedures (always) 他们为什么要这样做; Microsoft 确实为此保留了一个名为CommandType 的属性,用于选择文本和或存储过程。 在这种情况下,将不同的字符串分配给同一个变量有什么问题; So that will leave you with wonky results,你能解释一下奇怪的结果吗?
  • 为什么要使用存储过程:关注点分离、抽象、安全、最佳实践,使用 SP 的原因有很多,请参阅this stack question
  • @ciammarino 我知道原因是什么,而且 SP 肯定很好用,我的意思是,为什么在这里使用一个;你提到它应该是。如果不合二为一,你觉得把它做成一个存储过程会解决这里的OP问题吗?
  • @ciammarino 很好,你确实提出了一个很好的建议,使用 SP,这很好,但 TBH 不是这里的问题。

标签: .net vb.net sqlite system.data.sqlite


【解决方案1】:

简单的回答是你不应该使用共享的sqlite数据库文件,它不稳定,数据库文件很容易损坏。使用mariadb/postgresql是一个更好的主意。

我认为您的问题与事务有关,您应该手动提交更改以在更新后立即更新数据库文件。

1. SQLiteTransaction trans = conn.BeginTransaction();
2. select max(id), insert...
3. trans.commit();

【讨论】:

    【解决方案2】:

    我使用的函数有点相当于Sql Server中的Scope_Identity。我没有 SqlLite 数据库,所以无法测试。我不确定您是否可以在 SqLite 中链接命令,但如果不能仅进行 2 个单独的查询。 ExecuteScalar 返回结果集中第一行的第一列,这是您想要的数字。

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim NewID As Long
        Using cn As New SQLiteConnection("Your connection string")
            Using cmd As New SQLiteCommand("INSERT INTO joblog (jobid) VALUES (123); Select last_insert_rowid()")
                NewID = CLng(cmd.ExecuteScalar())
            End Using
        End Using
        MessageBox.Show($"The new ID is {NewID}")
    End Sub
    

    【讨论】:

    • 我不想在每次插入后关闭和打开连接。
    • ADO.net 处理连接池。我找不到不关闭它的理由。如果要进行批量更新,请使用 DataAdapter.Update。
    【解决方案3】:

    当我使用任何一个实例向数据库中插入一行时,从其他实例读取时自动递增的值(ID)不正确

    怀疑这是因为您的连接和命令没有关闭/处置所以它们保持打开状态。

    连接的最佳建议是使用它,然后关闭/处理它。命令也是如此,请确保它们已被释放。

    这是一种方法:

     Dim intReturn As Integer
     sql = "SELECT max(ID) FROM joblog;"
    
     ' First query to get your scalar return value
     Using cnn As New New SQLiteConnection("Data Source=\\abc\xx\x_backup.db;Password=password;Connect Timeout=55;FailIfMissing=True")
        Using mycommand As New SQLiteCommand(sql, cnn)
           cnn.ParseViaFramework = True
           cnn.Open()
    
           intReturn = mycommand.ExecuteScalar
           MessageBox.Show(intReturn)
    
        End Using
     End Using
    
     ' Second query to actually do the insert
     sql = "INSERT INTO joblog (jobid) VALUES (123);"
     Using cnn As New New SQLiteConnection("Data Source=\\abc\xx\x_backup.db;Password=password;Connect Timeout=55;FailIfMissing=True")
        Using mycommand As New SQLiteCommand(sql, cnn)
           cnn.ParseViaFramework = True
           cnn.Open()
    
           intReturn = mycommand.ExecuteNonQuery()
           MessageBox.Show("Records affected " & intReturn)
    
        End Using
     End Using
    

    另外,请注意使用SQL Parameters,否则您可能容易受到 SQL 注入攻击。

    【讨论】:

    • “我怀疑这是因为您的连接和命令没有关闭/处置,所以它们保持打开状态。”所以当两个实例打开连接时,sqlite 无法处理数据库?
    • @IT 研究员它在编写时锁定了整个数据库...从技术上可以,但它是一种竞争条件,我自己已经看到了。
    猜你喜欢
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-14
    相关资源
    最近更新 更多