所以我在System.Data.SQLite和使用多个事务时遇到了一个有趣的问题。基本上我有以下代码失败:
using (IDbConnection connection1 = new SQLiteConnection("connectionstring"), connection2 = new SQLiteConnection("connectionstring"))
{
connection1.Open();
connection2.Open();
IDbTransaction transaction1 = connection1.BeginTransaction();
IDbTransaction transaction2 = connection2.BeginTransaction(); // Fails!
using(IDbCommand command = new SQLiteCommand())
{
command.Text = "CREATE TABLE artist(artistid int, artistname text);";
command.CommandType = CommandType.Text;
command.Connection = connection1;
command.ExecuteNonQuery();
}
using (IDbCommand command = new SQLiteCommand())
{
command.Text = "CREATE TABLE track(trackid int, trackname text);";
command.CommandType = CommandType.Text;
command.Connection = connection2;
command.ExecuteNonQuery();
}
transaction1.Commit();
transaction2.Commit();
}
从我所看到的,似乎System.Data.SQLite应该支持嵌套和扩展顺序事务。代码在第7行(声明第二个事务)失败,但有以下异常:
System.Data.SQLite.SQLiteException: The database file is locked
System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
System.Data.SQLite.SQLiteDataReader.NextResult()
System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()
有谁知道问题是什么或如何解决这个问题?我觉得并发事务对于任何数据库系统都是必不可少的,因此必须有一些方法可以做到这一点。
谢谢!
答案 0 :(得分:14)
OP正在2个连接上启动事务,这就是问题开始的地方,而不是多个事务本身。
SQLiteConnection conn = new SQLiteConnection("data source=:memory:");
conn.Open();
var command = conn.CreateCommand();
command.CommandText = "create table a (b integer primary key autoincrement, c text)";
command.ExecuteNonQuery();
var tran1 = conn.BeginTransaction();
var tran2 = conn.BeginTransaction();
var command1 = conn.CreateCommand();
var command2 = conn.CreateCommand();
command1.Transaction = tran1;
command2.Transaction = tran2;
command1.CommandText = "insert into a VALUES (NULL, 'bla1')";
command2.CommandText = "insert into a VALUES (NULL, 'bla2')";
command1.ExecuteNonQuery();
command2.ExecuteNonQuery();
tran1.Commit();
tran2.Commit();
command.CommandText = "select count(*) from a";
Console.WriteLine(command.ExecuteScalar());
答案 1 :(得分:3)
SQLite被设计为轻量级数据库,用于浏览器中的书签或照片目录程序中的照片。 SQLite有一个非常精细的锁定系统,该系统针对具有许多读取器或单个读取器/写入器线程的场景进行了优化。因此,众所周知,并发写入存在性能问题 - 它根本不适用于具有许多优秀编写器的应用程序。您可以执行并发写入,但它不能很好地扩展。
在这种情况下,问题是因为您尝试进行并发架构更改 - 如果您改为执行多个SELECT
或多个INSERT
语句,则此将成功运行(正如sixfeetsix的答案所示。)
如果您的应用程序有很多读者而不是很多编写者,那么SQLite可能会很好,但如果您的应用程序包含许多并发读者和编写者,那么您可能会发现完全成熟的数据库服务器是更合适。
答案 2 :(得分:1)
尝试使用:
((SQLiteConnection)connection).BeginTransaction(true)-
bool参数讲述了deferredLock。但是,请记住,只有在提交第一个事务后才应调用ExecuteNonScalar。
答案 3 :(得分:-1)
对于它的价值,不支持每个连接的多个事务似乎对数据提供者来说很常见(我肯定知道ODP.NET,可能是其他人)。
解决此问题的一种方法是为每个单独的IDbConnection
单独IDbTransaction
。
- 编辑---
卫生署!我刚刚意识到你做有多个连接。遗憾。
答案 4 :(得分:-1)
SQLite不支持多个事务 - 它在事务中锁定整个数据库(参见www.sqlite.org)。
编辑: 支持多个事务,但在多个事务中使用DDL时则不支持。