获取最后插入的ID

3

我目前使用以下方法获取最后插入行的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?

2个回答

6

如果在此期间另一个客户端/连接插入记录,下面的代码会返回错误的行 ID 吗?

不会,因为写操作要么在读操作之后进行,要么在读操作之前进行,但不会在读操作期间进行。

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

当然可以。

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

如果还没有,请阅读SQLite 的文件锁定模型


1
代码中的注释问题与其余问题相同。注释行仅用于标记我认为另一个客户端实例可以插入记录的时间。 - rafale
好的。只是为了明确,注释行并没有指示比“SELECT”之前更具体的时间。 - Matt Ball
是的,“在SELECT之前”就是我想说的。一开始你为什么回答不确定让我有些疑惑。在读取期间不会发生写入,但是一个客户端的写入可能会在另一个客户端的读取之前发生。那个客户端将获得由其他客户端插入的行的ID。理想情况下,我希望SQLite在INSERT之后立即进行锁定,然后在SELECT之后释放。 - rafale
我明白了。修复方法是通过更改“Database.ExecuteNonQuery()”调用为一个在一个事务中写入和读取的调用(我猜测是“Database.ExecuteWithResults()”?我真的不是C#开发人员),从而消除单个客户端写入和读取之间的窗口。 - Matt Ball

2
如果插入命令和获取最后插入行ID命令都在同一个写锁内,并且在这两个命令之间没有其他插入命令可以运行,则是安全的。
如果您在插入命令之后开始写锁定,那么就无法确定另一个线程是否首先获得了写锁定。如果另一个线程确实首先获取了写锁定,则在该线程释放其锁定之前,您将无法执行对行ID的搜索。那时候,如果另一个线程插入了新行,可能就太晚了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接