我在使用SQLite时遇到以下情况。
有两个线程正在处理数据库。
两个线程都必须在事务中插入消息。
因此,如果说一个线程在插入20k行后提交,而其他线程尚未提交。
在输出中,我看到所有已提交的数据已被线程2插入,直到线程1提交数据为止。
示例功能:
/// <summary>
/// Inserts list of messages in message table
/// </summary>
/// <param name="listMessages"></param>
/// <returns></returns>
public bool InsertMessages(IList<MessageBase> listMessages, bool commitTransaction)
{
bool success = false;
if (listMessages == null || listMessages.Count == 0)
return success;
DatabaseHelper.BeginTransaction(_sqlLiteConnection);
foreach (MessageBase message in listMessages)
{
using (var statement = _sqlLiteConnection.Prepare(_insertMessageQuery))
{
BindMessageData(message, statement);
SQLiteResult result = statement.Step();
success = result == SQLiteResult.DONE;
if (success)
{
Debug.WriteLine("Message inserted suucessfully,messageId:{0}, message:{1}", message.Id, message.Message);
}
else
{
Debug.WriteLine("Message failed,Result:{0}, message:{1}", result, message.Message);
}
}
}
if (commitTransaction)
{
Debug.WriteLine("Data committed");
DatabaseHelper.CommitTransaction(_sqlLiteConnection);
}
else
{
Debug.WriteLine("Data not committed");
}
return success;
}
有没有办法阻止线程2插入的提交事务?
答案 0 :(得分:0)
简而言之,单个数据库无法实现。
单个sqlite数据库不能有多个具有单独事务上下文的同时写入程序。 sqlite数据库每个连接也没有单独的上下文;要获取上下文,您需要建立新连接。但是,只要使用insert(或update / delete)启动初始写入,事务就需要对数据库执行RESERVED锁定(允许读取器,不允许其他编写器),这意味着无法进行并行写入。我认为您可以使用SAVEPOINT
和RELEASE
伪造它,但这些也是在连接上序列化的,并且不会生成单独的上下文。
考虑到这一点,只要两个线程都没有写入同一个表,您就可以使用使用ATTACH DATABASE
连接的单独数据库。为此,您将在运行时附加包含其他表的附加数据库。但是,您仍然需要为每个并行编写器提供单独的连接,因为提交连接仍然适用于所有打开的事务。
否则,您可以通过打开其他连接和后续连接来获得单独的交易。事务只需要等到RESERVED锁被释放。
参考文献: