尽管我不回滚事务,但 SQLite 事务未成功?
创建连接+事务:
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()){...}
Create the Connection + Transaction:
public SQLiteTransaction BeginTransaction()
{
var con = new SQLiteConnection(@"Data Source=A:\TransactionScopeTest\TransactionTest.db;Foreign Keys=ON");
con.Open();
var trans = con.BeginTransaction();
return trans;
}
Do 2 sqlite inserts with same Primary Key value to raise an exception
[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;
}
}
}
As I use SQLite its best practice to use the SQLiteTransaction class for every executed sql command.
The connection from the transaction needs to be shared among the dataprovider methods.
I am asking YOU now multiple questions:
1.) When a SQLiteException occurs because of inserting same primary keys "John" there is not inserted any of the "John" values. That is ok because I used a transaction and the .Commit() must be executed. What bothers me is WHY does it not make any difference wether OR NOT I use trans.Rollback() in the catch-block.
2.) I am using the "using(resource)"-statement so what will happen if the transaction succeeds/commits to the state of the connection ? Will it be closed? Just concern that I do not do use the `using(var trans = new SQLiteTransaction()){...}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
回答你的问题:
不过,我注意到的一件事是,您创建的命令对象不与事务关联。如果要针对 SQL Server 或 Oracle 执行此代码,则会抛出异常,指出所有命令必须分配活动事务(如果有)。
要将命令与事务关联起来,在创建每个新命令对象后,您将需要以下代码:
通常,我的数据库代码遵循以下格式:
上面的连接流程将确保所有与连接、事务相关的资源,并且命令对象在发生异常时被清理。如果抛出异常,则错误位于抛出异常的行,而不是捕获并再次抛出异常的 catch 块。此外,事务将被回滚,并且底层数据库连接将被关闭(或返回到池中,如果存在的话)。
请记住,如果某个东西有
Dispose()
方法并实现了IDisposable
接口,最好将其包装在 using 语句中,因为即使调用Dispose( )
现在什么都不做,不能保证将来会这样。To answer your questions:
One thing I noticed, though, is that your command objects you've created are not associated with the transaction. If this code were to be executed against SQL server or Oracle an exception would be thrown stating that all commands must be assigned the active transaction (if there is one).
To associate the command with the transaction you'll need the following piece of code after each new command object created:
Typically my database code follows the format of:
This flow of the connections above will ensure that all related resources with the connection, the transaction, and the command object are cleaned up in the event of an exception. If an exception is thrown, the error is on the line that threw it, not the catch block that caught and threw it again. In addition, the transaction would be rolled back and the underlying database connection would be closed (or returned to the pool, if one existed).
Remember, if something has a
Dispose()
method and implements theIDisposable
interface, it is best to wrap it in a using statement, because even if callingDispose()
does nothing now, there is no guarantee it will be that way in the future.因为事务存在隐式回滚。提交必须是明确的。
连接最终将由运行时关闭。
Because there is an implicit rollback with transactions. Commits have to be explicit.
The connection will be closed eventually by the runtime.