原文网址:https://www.cnblogs.com/fanfan-90/p/16296737.html
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();
}
}
}
事务的四个特性
原文网址:https://baijiahao.baidu.com/s?id=1717564719318727121
答:原子性、一致性、隔离性、持久性
原子性事务中的操作为一个整体,要么都做,要么都不做.即一旦事务出错,就回滚事务
一致性事务:执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。
如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
隔离性:一个事务的执行不能被其他事务干扰。即一个事物内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事物之间不能互相干扰
持久性:指一个事物一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响
事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)