在 SQLite 中尝试将记录列表从一个 table 移动到另一个 table 时获取 "Database is Locked"
Getting "Database is Locked" when trying to move a list of records from one table to another table in SQLite
我有一个 Public Sub 可以将记录集合从一个 table 移动到同一 SQLite 数据库中的另一个。首先它从 strFromTable 中读取一条记录,然后将其写入 strToTable,然后从 strFromTable 中删除该记录。为了加快速度,我已将整个记录集合加载到事务中。当列表涉及移动大量图像 blob 时,数据库会备份,并抛出异常“数据库已锁定”。我认为正在发生的事情是它在开始尝试写入下一条记录之前还没有完成一条记录的写入。由于 SQLite 一次只允许一个写入,它会抛出“锁定”异常。
以下是移动大量图像 blob 时触发错误的代码:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
tr.Commit()
End Using
End Using
当我删除事务时,它执行时没有错误:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
End Using
我不太擅长数据库操作,所以我确信有一些地方需要改进。有没有办法让SQLite在执行下一个INSERT之前完全完成之前的INSERT?如何更改我的代码以允许使用交易?
感谢您的帮助。
.
好的...这是我决定采用的解决方案。我希望这有助于有人在搜索中找到它:
Dim arrIds(lvcollection.Count - 1) As String
Dim i as Integer = 0
' Load the array with all the Tags in the listViewCollection
For i = 0 to lvcollection.Count - 1
arrIds(i) = lvcollection(i).Tag 'item.Tag holds the Primary Key "id" field in the DB
Next
'build a comma-space separated string of all ids from the array of ids.
Dim strIds as String = String.Join(", ", arrIds)
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id IN ({strIds});"
SQLcommand.ExecuteNonQuery()
SQLcommand.CommandText = $"DELETE FROM {strFromTable} WHERE ID IN ({strIds});"
SQLcommand.ExecuteNonQuery()
End Using
tr.Commit()
End Using
End Using
IN 语句允许我传递所有要批量删除的“id”值。这种解决方案比没有事务的一个一个地执行它们更快、更安全。
感谢您的评论,祝大家编码顺利。
我有一个 Public Sub 可以将记录集合从一个 table 移动到同一 SQLite 数据库中的另一个。首先它从 strFromTable 中读取一条记录,然后将其写入 strToTable,然后从 strFromTable 中删除该记录。为了加快速度,我已将整个记录集合加载到事务中。当列表涉及移动大量图像 blob 时,数据库会备份,并抛出异常“数据库已锁定”。我认为正在发生的事情是它在开始尝试写入下一条记录之前还没有完成一条记录的写入。由于 SQLite 一次只允许一个写入,它会抛出“锁定”异常。
以下是移动大量图像 blob 时触发错误的代码:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
tr.Commit()
End Using
End Using
当我删除事务时,它执行时没有错误:
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using SQLcommand = SQLconnect.CreateCommand
For Each itm As ListViewItem In lvcollection
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id = {itm.Tag}; DELETE FROM {strFromTable} WHERE ID = {itm.Tag};"
SQLcommand.ExecuteNonQuery()
Next
End Using
End Using
我不太擅长数据库操作,所以我确信有一些地方需要改进。有没有办法让SQLite在执行下一个INSERT之前完全完成之前的INSERT?如何更改我的代码以允许使用交易?
感谢您的帮助。
.
好的...这是我决定采用的解决方案。我希望这有助于有人在搜索中找到它:
Dim arrIds(lvcollection.Count - 1) As String
Dim i as Integer = 0
' Load the array with all the Tags in the listViewCollection
For i = 0 to lvcollection.Count - 1
arrIds(i) = lvcollection(i).Tag 'item.Tag holds the Primary Key "id" field in the DB
Next
'build a comma-space separated string of all ids from the array of ids.
Dim strIds as String = String.Join(", ", arrIds)
Using SQLconnect = New SQLiteConnection(strDbConnectionString)
SQLconnect.Open()
Using tr = SQLconnect.BeginTransaction()
Using SQLcommand = SQLconnect.CreateCommand
SQLcommand.CommandText = $"INSERT INTO {strToTable} SELECT * FROM {strFromTable} WHERE id IN ({strIds});"
SQLcommand.ExecuteNonQuery()
SQLcommand.CommandText = $"DELETE FROM {strFromTable} WHERE ID IN ({strIds});"
SQLcommand.ExecuteNonQuery()
End Using
tr.Commit()
End Using
End Using
IN 语句允许我传递所有要批量删除的“id”值。这种解决方案比没有事务的一个一个地执行它们更快、更安全。
感谢您的评论,祝大家编码顺利。