【问题标题】:Getting last inserted ID获取最后插入的 ID
【发布时间】:2011-08-26 08:07:15
【问题描述】:

我目前正在使用下面的方法来获取最后插入的行的ID。

    Database.ExecuteNonQuery(query, parameters);

    //if another client/connection inserts a record at this time, 
    //could the line below return the incorrect row ID?
    int fileid = Convert.ToInt32(Database.Scalar("SELECT last_insert_rowid()"));
    return fileid;

到目前为止,这种方法运行良好,但我不确定它是否完全可靠。

假设有两个客户端应用程序,每个都有自己独立的数据库连接,它们同时调用上面的服务器端方法。请记住,客户端线程并行运行并且 SQLite 一次只能运行一个操作(或者我听说过),一个客户端实例是否有可能返回由插入的记录的行 ID另一个实例?

最后,有没有更好的方法来获取最后插入的行 ID?

【问题讨论】:

    标签: c# sqlite system.data.sqlite


    【解决方案1】:

    如果此时另一个客户端/连接插入一条记录,下面的行是否会返回错误的行ID?

    不,因为写入要么发生在读取之后,要么发生在读取之前,但不会在读取期间发生。

    请记住,客户端线程并行运行并且 SQLite 一次只能运行一个操作,一个客户端是否有可能获取另一个客户端插入的记录的行 ID?

    是的,当然。

    同时调用服务器端方法并不重要。数据库的锁定允许并发读取,但不允许并发写入,或边写边读取。

    如果您还没有,请阅读SQLite's file locking model

    【讨论】:

    • 代码中注释的问题与问题的其余部分提出的问题相同。注释行仅用于标记我认为另一个客户端实例可以插入记录的时间。
    • 好的。不过,我们很清楚,注释行并不表示比“SELECT 之前”更具体的时间。
    • 是的,“在 SELECT 之前”就是我的意思。我只是不确定你为什么一开始回答不。在读取期间不会发生写入,但来自一个客户端的写入可能会在读取另一个客户端之前发生。然后,该客户端将获得另一个客户端插入的行的 ID。理想情况下,我会让 SQLite 在 INSERT 之后立即执行锁定,然后在 SELECT 之后释放。
    • 我跟着。解决方法是通过将Database.ExecuteNonQuery() 调用更改为在一个事务中写入和读取所有内容的调用来消除单个客户端写入和读取之间的窗口(我猜Database.ExecuteWithResults()?我真的不是 C# 开发人员)。
    【解决方案2】:

    如果插入命令和获取最后插入的行 ID 命令都在同一个写锁内,并且该写锁中没有其他插入命令可以在这两个命令之间运行,那么你是安全的。

    如果您在插入命令之后启动写锁,则无法确定另一个线程没有首先获得写锁。如果另一个线程确实首先获得了写锁,那么在其他线程释放它们的锁之前,您将无法执行对行 ID 的搜索。到那时,如果其他线程插入新行可能为时已晚。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-27
      • 1970-01-01
      • 2013-05-19
      相关资源
      最近更新 更多