事务的使用
Fireasy 的事务是一个 Scope
级别的,即在一次请求期间(即使异步也是),一旦开启了事务,使用相同连接串的不同 Database
或 EntityContext
均会使用同一个事务对象,且事务的提交或回滚只会在开启事务的代码块内有效,这就避免了事务嵌套所带来的误提交或回滚问题。在 EntityContext
里使用事务,有以下几种方法。
1、Begin / Commit / Rollback
使用 BeginTransaction 开启一个事务,如果此时已经有一个事务对象,则此操作将被忽略。使用 CommitTransaction 方法提交一个事务,如果当前的事务对象不是由此 EntityContext
所开启的,则此操作也将忽略。使用 RollbackTransaction 方法回滚事务,其规则与 CommitTransaction 一样。
标准调用示例如下:
[TestMethod]
public void TestTrans()
{
using (var db = new DbContext())
{
try
{
//事务开启
db.BeginTransaction();
//其他处理
//事务提交
db.CommitTransaction();
}
catch
{
db.RollbackTransaction();
}
}
}
下面的示例是事务的嵌套情况,DbContext1
和 DbContext2
使用不同的数据库连接。
[TestMethod]
public void TestTrans()
{
using (var db = new DbContext1())
{
//事务开启
db.BeginTransaction();
TestNestedTrans1();
//事务提交
db.CommitTransaction();
}
}
private void TestNestedTrans1()
{
using (var db = new DbContext1())
{
//由于与 TestTrans 使用的是同一个连接,因此此方法里的 Begin 和 Commit 均被忽略
db.BeginTransaction();
TestNestedTrans2();
TestNestedTrans3();
db.CommitTransaction();
}
}
private void TestNestedTrans2()
{
using (var db = new DbContext2())
{
//事务开启
db.BeginTransaction();
db.Database.ExecuteNonQuery((SqlCommand)"delete from orders where orderid=-1");
//事务提交
db.CommitTransaction();
}
}
private void TestNestedTrans3()
{
using (var db = new DbContext1())
{
//由于与 TestTrans 使用的是同一个连接,因此此方法里的 Begin 和 Commit 均被忽略
db.BeginTransaction();
db.Database.ExecuteNonQuery((SqlCommand)"delete from orders where orderid=-1");
db.CommitTransaction();
}
}
2、EntityTransactionScope
可以使用 EntityTransactionScope
统一来开启事务,它会管理不同数据库连接的事务对象,最后调用 Complete 方法提交所有的数据库事务。
[TestMethod]
public async Task TestTransScope()
{
using (var scope = new EntityTransactionScope())
{
using (var db = new DbContext1())
{
await db.Products.DeleteAsync(s => false);
}
using (var db = new DbContext2())
{
await db.Products.DeleteAsync(s => false);
}
scope.Complete();
}
}
3、UseTransaction 扩展方法
EntityContext
有一组扩展方法用于开启事务并将事务体放在委托里,它实际上是对 Begin / Commit / Rollback 的包装。
[TestMethod]
public void TestTrans()
{
using (var db = new DbContext())
{
//事务开启
db.UseTransaction(db =>
{
//其他处理
}, throwExp: exp =>
{
//异常处理
});
}
}
4、UnitOfWork
//todo 暂未提供。