创建连接 + 交易:
public SQLiteTransaction BeginTransaction()
{
var con = new SQLiteConnection(@"Data Source=A:\TransactionScopeTest\TransactionTest.db;Foreign Keys=ON");
con.Open();
var trans = con.BeginTransaction();
return trans;
}
使用相同的主键值执行 2 个 sqlite 插入以引发异常
[TestMethod]
public void TestMethod1()
{
using (var trans = BeginTransaction())
{
try
{
SQLiteConnection con = trans.Connection;
SQLiteCommand cmd1 = con.CreateCommand();
cmd1.CommandText = "INSERT INTO TEST(Name) VALUES('John')";
cmd1.ExecuteNonQuery();
SQLiteCommand cmd2 = con.CreateCommand();
cmd2.CommandText = "INSERT INTO TEST(Name) VALUES('John')";
cmd2.ExecuteNonQuery();
trans.Commit();
}
catch (Exception)
{
trans.Rollback();
throw;
}
}
}
当我使用 SQLite 时,它的最佳实践是为每个执行的 sql 命令使用 SQLiteTransaction 类。
来自事务的连接需要在数据提供者方法之间共享。
我现在问你多个问题:
1.) 当由于插入相同的主键“John”而发生 SQLiteException 时,不会插入任何“John”值。没关系,因为我使用了一个事务并且 .Commit() 必须被执行。困扰我的是为什么我在 catch 块中使用 trans.Rollback() 没有任何区别。
2.) 我正在使用“using(resource)”语句,那么如果事务成功/提交到连接状态会发生什么?它会被关闭吗?只是担心我不使用 `using(var trans = new SQLiteTransaction()){...}
最佳答案
回答您的问题:
不过,我注意到的一件事是,您创建的命令对象是 而不是与事务关联的 。如果要针对 SQL Server 或 Oracle 执行此代码,则会抛出异常,指出必须将所有命令分配给事件事务(如果有)。
要将命令与事务相关联,在创建每个新命令对象后,您需要以下代码:
cmd.Transaction = trans;
通常我的数据库代码遵循以下格式:
using (SqlConnection connection = new SqlConnection("...")) {
connection.Open();
using (SqlTransaction transaction = connection.BeginTransaction())
using (SqlCommand command = connection.CreateCommand()) {
command.Transaction = transaction;
command.CommandText = "INSERT INTO ...";
// add parameters...
command.ExecuteNonQuery();
transaction.Commit();
}
// Reference to question 1: At this point in the code, assuming NO unhandled
// exceptions occurred, the connection object is still open and can be used.
// for example:
using (SqlCommand command = connection.CreateCommand()) {
command.CommandText = "SELECT ...";
using (SqlDataReader reader = command.ExecuteReader()) {
while (reader.Read()) {
// do awesome processing here.
}
}
}
}
上述连接流将确保在发生异常时清除所有与连接、事务和命令对象相关的资源。如果抛出异常,则错误在抛出它的行上,而不是在捕获并再次抛出它的 catch 块上。此外,事务将被回滚并且底层数据库连接将被关闭(或返回到池中,如果存在的话)。
请记住,如果某个东西具有
Dispose()
方法并实现了 IDisposable
接口(interface),最好将其包装在 using 语句中,因为即使现在调用 Dispose()
什么都不做,也不能保证将来会如此。关于c# - 虽然我没有回滚我的事务,但 SQLite 事务没有成功?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7334312/