【EF Core】三种事务(SaveChange、DBContextTransaction、TransactionScope)
EF中的事务主要分为三类,分别是SaveChanges
、DbContextTransaction
、TransactionScope
。
SaveChanges
SaveChanges一次性将本地缓存中所有的状态变化一次性提交到数据库,这就是一个事务,要么统一成功,要么统一回滚。
使用场景:一个DBContext,即一个数据库的EF的上下文,不能控制多个数据库。
DbContextTransaction事务
通常用于手动接管事务,某些操作是一个事务,某些操作是另外一个事务。
使用场景:EF调用SQL语句的时候使用该事务、 多个SaveChanges;不同控制多个数据库
private static void TestDbContextTransactionFailure()
{
using (DbContext db = new CodeFirstModel())
{
DbContextTransaction trans = null;
try
{
//开启事务
trans = db.Database.BeginTransaction();
//增加
string sql1 = @"insert into TestInfor values(@id,@txt1,@txt2)";
SqlParameter[] pars1 ={
new SqlParameter("@id",Guid.NewGuid().ToString("N")),
new SqlParameter("@txt1","txt11"),
new SqlParameter("@txt2","txt22")
};
db.Database.ExecuteSqlCommand(sql1, pars1);
//修改
string sql3 = @"update TestInfor set txt1=@txt1 where id=@id";
SqlParameter[] pars3 ={
new SqlParameter("@id","3"),
new SqlParameter("@txt1","二狗子222")
};
db.Database.ExecuteSqlCommand(sql3, pars3);
//提交事务
trans.Commit();
Console.WriteLine("事务成功了");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
trans.Rollback();
}
finally
{
trans.Dispose();
}
}
}
TransactionScope事务
该事务用来处理多个SaveChanges的事务(特殊情况的业务)或者多个DBContext(每个DBContext是一个实例,代表不同的数据库连接).
如果使用该事务来处理多个数据库(多个DBContex)时,必须手动开启msdtc服务,这样才可以将多个DB的SaveChange给放到一个事务中
使用场景:
- 多数据库连接的情况
- 主键id自增的情况,同一个业务线中,需要拿到新增加的数据的主键id,进行操作。
主键自增被使用的情况的解决方案
private static void Test3()
{
using (DbContext db = new CodeFirstModel())
{
using (TransactionScope trans = new TransactionScope())
{
try
{
TestInfor2 t1 = new TestInfor2()
{
txt11 = Guid.NewGuid().ToString("N"),
txt22 = Guid.NewGuid().ToString("N")
};
db.Set<TestInfor2>().Add(t1);
//如果这里不写SaveChanges的话,t1.id永远为0
db.SaveChanges();
TestInfor2 t2 = new TestInfor2()
{
txt11 = (t1.id + 1).ToString(),
txt22 = Guid.NewGuid().ToString("N")
};
db.Entry(t2).State = EntityState.Added;
db.SaveChanges();
//事务统一提交(若失败则统一回滚)
trans.Complete();
Console.WriteLine("自增提交成功");
}
catch (Exception)
{
Transaction.Current.Rollback();
}
}
}
}
多个DBContext、多个数据库的情况。
private static void TransactionScopeTwoDB()
{
using (TransactionScope trans = new TransactionScope())
{
try
{
DbContext db1 = new CodeFirstModel();
DbContext db2 = new CodeFirstModel2();
//数据库1
TestInfor t1 = new TestInfor()
{
id = Guid.NewGuid().ToString("N"),
txt1 = "111111111",
txt2 = "222222222222"
};
db1.Entry(t1).State = EntityState.Added;
db1.SaveChanges();
//数据库2
TestOne t2 = new TestOne()
{
id = Guid.NewGuid().ToString("N"), //可以在此处手动制造个错误,来测试多数据库的回滚问题
t1 = "222",
t2 = "2222"
};
db2.Entry(t2).State = EntityState.Added;
db2.SaveChanges();
trans.Complete();
Console.WriteLine("多个数据库添加成功");
}
catch (Exception)
{
Transaction.Current.Rollback();
}
}
}