EF 事务(转载)
事务简单用法
文章一:https://www.cnblogs.com/wujingtao/p/5407821.html
1EF事务
事务就是确保一次数据库操作,所有步骤都成功,如果哪一步出错了,整个操作都将回滚。
在EF使用事务有两种方案,一种是EF自带的.BeginTransaction()方法,另一种是使用TransactionScope类。
使用.BeginTransaction()
使用.BeginTransaction()实现事务
class Program
{
static void Main(string[] args)
{
using (var db = new DBModel())
{
var tran = db.Database.BeginTransaction(); //开启事务 try
{
var student = db.students.FirstOrDefault(s => s.name == "萝莉");
db.students.Remove(student); //删除萝莉 db.SaveChanges(); tran.Commit(); //必须调用Commit(),不然数据不会保存
}
catch (Exception ex)
{
tran.Rollback(); //出错就回滚
}
}
}
}
使用TransactionScope类
使用之前记得引入System.Transactions.dll
使用TransactionScope
class Program
{
static void Main(string[] args)
{
using (var db = new DBModel())
{
using (var tran = new TransactionScope()) //开启事务
{
var student = db.students.FirstOrDefault(s => s.name == "萝莉");
db.students.Remove(student); //删除萝莉 db.SaveChanges(); tran.Complete(); //必须调用.Complete(),不然数据不会保存
} //出了using代码块如果还没调用Complete(),所有操作就会自动回滚
}
}
}
文章二:https://www.cnblogs.com/CreateMyself/p/4787856.html#!comments
事务复杂用法
1概念
在开始学习事务之前我们先了解两个概念:
- Database.BeginTransaction():它是在一个已存在的DbContext上下文中对于我们去启动和完成transactions的一种简单方式,它允许多个操作组合存在在相同的transaction中,所以要么提交要么全部作为一体回滚,同时它也允许我们更加容易的去显示指定transaction的隔离级别。
- Dtabase.UseTransaction():它允许DbContext上下文使用一个在EF实体框架之外启动的transaction。
2默认事务
当我们调用SaveChanges方法来执行增、删、改时其操作内部都用一个transaction包裹着(自动完成的)。如下图,当添加数据时:
- 对于上下文中的 ExecuteSqlCommand() 方法默认情况下也是用transaction包裹着命令(Command),其有重载我们可以显示指定执行事务还是不确定执行事务。
- 在此上两种情况下,事务的隔离级别是数据库提供者认为的默认设置的任何隔离级别,例如在SQL Server上默认是READ COMMITED(读提交)。
- EF对于任何查询都不会用transaction来进行包裹。
在EF 6.0版本以上,EF一直保持数据库连接打开,因为要启动一个transaction必须是在数据库连接打开的前提下,同时这也就意味着我们执行多个操作在一个transaction的唯一方式是要么使用 TransactionScope 要么使用 ObjectContext.Connection 属性并且启动调用Open()方法以及BeginTransaction()方法直接返回EntityConnection对象。如果你在底层数据库连接上启动了transaction,再调用API连接数据库可能会失败。
3同一上下文中使用transaction
Database.BeginTransaction有两种重载——一种是显示指定隔离级别,一种是无参数使用来自于底层数据库提供的默认隔离级别,两种都是返回一个DbContextTransaction对象,该对象提供了事务提交(Commint)以及回滚(RollBack)方法直接表现在底层数据库上的事务提交以及事务回滚上。
DbContextTransaction一旦被提交或者回滚就会被Disposed,所以我们使用它的简单的方式就是使用using(){}语法,当using构造块完成时会自动调用Dispose()方法。
根据上述我们现在通过两个步骤来对学生进行操作,并在同一transaction上提交。如下:

using (var ctx = new EntityDbContext())
{ using (var ctxTransaction = ctx.Database.BeginTransaction())
{ try
{
ctx.Database.Log = Console.WriteLine; ctx.Database.ExecuteSqlCommand("update student set name='xpy0929'"); var list = ctx.Set<Student>().Where(p => p.Name == "xpy0929").ToList(); list.ForEach(d =>
{ d.Name = "xpy0928"; }); ctx.SaveChanges(); ctxTransaction.Commit();
}
catch (Exception)
{
ctxTransaction.Rollback();
} }
}

我们通过控制台输出SQL日志查看提交事务成功如下:
【注意】 要开始一个事务必须保持底层数据库连接是打开的,如果数据库不总是打开的我们可以通过 BeginTransaction() 方法将打开数据库连接,如果 DbContextTransaction 打开了数据库,当调用Disposed()方法时将会关闭数据库连接。
4注意事项
1一定要用using包裹,保证每次上下文会新建和释放,这个上下文不可与其它方法共用。
2当用EF上下文中的 Database.ExecuteSqlCommand 方法来对数据库进行如下操作时

using (var ctx = new EntityDbContext())
{ var sqlCommand = String.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", "DBConnectionString");
ctx.Database.ExecuteSqlCommand(sqlCommand); }

此时将会报错如下:
上述已经讲过此方法会被Transaction包裹着,所以导致出错,但是此方法有重载,我们进行如下设置即可
ctx.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,sqlCommand);
5将一个已存在的事务添加到上下文中
有时候我们可能需要事务的作用域更加广一点,当然是在同一数据库上但是是在EF之外完全进行操作。基于此,此时我们必须手动打开底层的数据库连接来启动事务,同时通知EF使用我们手动打开的连接来使现有的事务连接在此连接上,这样就达到了在EF之外使用事务的目的。
为了实现上述在EF之外使用事务我们必须在DbContext上下文中的派生类的构造器中关闭自身的连接而使用我们传入的连接。
第一步
上下文中关闭EF连接使用底层连接。
代码如下:
public EntityDbContext(DbConnection con)
: base(con, contextOwnsConnection: false)
{ }
第二步
启动Transcation(如果我们想避免默认设置我们可以手动设置隔离级别),通知EF一个已存在的Transaction已经在我们手动的设置的底层连接上启动。

using (var con = new SqlConnection("ConnectionString"))
{
using (var SqlTransaction = con.BeginTransaction())
{
using (var ctx = new EntityDbContext(con))
{
}
}
}

第三步
因为此时是在EF实体框架外部执行事务,此时则需要用到上述所讲的 Database.UseTransaction 将我们的事务对象传递进去。
ctx.Database.UseTransaction(SqlTransaction);
此时我们将能通过SqlConnection实例来自由执行数据库操作或者说是在上下文中,执行的所有操作都是在一个Transaction上,而我们只负责提交和回滚事务并调用Dispose方法以及关闭数据库连接即可。
至此给出完整代码如下:

using (var con = new SqlConnection("ConnectionString"))
{
con.Open();
using (var SqlTransaction = con.BeginTransaction())
{
try
{
var sqlCommand = new SqlCommand();
sqlCommand.Connection = con;
sqlCommand.Transaction = SqlTransaction;
sqlCommand.CommandText =
@"update student set name = 'xpy0929'";
sqlCommand.ExecuteNonQuery(); using (var ctx = new EntityDbContext(con))
{ ctx.Database.UseTransaction(SqlTransaction); var list = ctx.Set<Student>().Where(d => d.Name == "xpy0929").ToList(); list.ForEach(d => {
d.Name = "xpy0928";
}); ctx.SaveChanges(); } SqlTransaction.Commit();
}
catch (Exception)
{
SqlTransaction.Rollback(); }
} }

【注意】你可以设置 ctx.Database.UseTransaction(null); 为空来清除当前EF中的事务,如果你这样做了,那么此时EF既不会提交事务也不会回滚现有的事务,除非你清楚这是你想做的 ,否则请谨慎使用。
6 TransactionScope Transactions
在msdn上对 TransactionScope 类定义为是:类中的代码称为事务性代码。
我们将上述代码包含在如下代码中,则此作用域里的代码为事务性代码
using ( var scope = new TransactionScope(TransactionScopeOption.Required))
{ }
【注意】此时SqlConnection和EF实体框架都使用 TransactionScope ,因此此时将被会一起提交。
在.NET 4.5.1中 TransactionScope 能够和异步方法一起使用通过TransactionScopeAsyncFlowOption的枚举来启动。
通过如下实现:
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{}
接着就是将数据库连接的打开方法(Open)、查询方法(ExecuteNonQuery)、以及上下文中保存的方法(SaveChanges)都换为对应的异步方法(OpenAsync)、(ExecuteNonQueryAsync)以及(SaveChangesAsync)即可
EF 事务(转载)的更多相关文章
- 分享我们项目中基于EF事务机制的架构 【转载】
http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html 写在前面: 1. 本文中单元测试 ...
- 分享我们项目中基于EF事务机制的架构
写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...
- EF 事务
http://yanwushu.byethost7.com/?p=87 1. EF对事务进行了封装:context的saveChange()是有事务性的. 2. 依赖多个不同的Context的操作(即 ...
- EF 事务(非分布式事务)
在EF 中怎么使用事务? 这个问题纠结了我好久,直到有人跟我一起讨论,我和同事一起讨论查资料. 查的好多资料都是使用 TransactionScope,用 TransactionScope 可处理分布 ...
- EF事务嵌套
EF中采用的是数据上下文DbContext,当针对数据库的所有操作共用一个数据上下文的时候,会使用同一个连接对象,因此连接打开一次,最后Save的时候关闭连接,避免了频繁的创建连接对象打开关闭,这在一 ...
- MySql EF事务using不会自动 Rollback的bug
EF to MySql一般都是用using最后Commit,一直以为最后没Commit,当using调用Dispose会自动Rollback,没想到这儿有个坑,mysql有个bug并不会Rollbac ...
- 第六章 springboot + 事务(转载)
本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5350106.html 在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. myba ...
- 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载
原文:http://www.ite/topic/122700 9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XA ...
- EF事务封装
public class EFTransaction:ITransaction { DbContextTransaction originalTransaction = null; MyDbConte ...
随机推荐
- VS 快捷键使用
代码注释与整理 Ctrl+K+C:注释所选代码块 Ctrl+K+U:取消代码块注释 Ctrl+K+D:整理对齐整个代码区 Ctrl+K+F:整理对齐所选代码块 选择代码 Home:跳转行首 End:跳 ...
- 吴恩达机器学习笔记7-梯度下降III(Gradient descent intuition) --梯度下降的线性回归
梯度下降算法和线性回归算法比较如图: 对我们之前的线性回归问题运用梯度下降法,关键在于求出代价函数的导数,即: 我们刚刚使用的算法,有时也称为批量梯度下降.实际上,在机器学习中,通常不太会给算法起名字 ...
- Docker学习笔记-简单运行.netcore
前言: 环境:centos7.5 64 位 正文: 拉取 microsoft/dotnet, 安装完毕后执行 docker images 可以看到本地已经包含 microsoft/dotnet #包含 ...
- Go语言结构
目录 结构体定义 创建结构体实例 普通方式创建结构体实例 new()创建结构体实例 结构体实例初始化 结构体类型实例和指向它的指针内存布局 结构体的方法 面向对象 组合(继承) 结构体使用注意事项 G ...
- 画线动画——SVG版和纯CSS版
概述 我们常常在网站中看到一些画线的动画效果,非常炫酷,大多数这种画线动画效果是通过SVG实现的,也有不少是用纯css实现的,下面我总结了一下这2种方法,供以后开发时参考,相信对其他人也有用. 参考资 ...
- MngoDb MongoClientOptions 配置信息及常用配置信息
MongoClientOptions.Builder addClusterListener(ClusterListener clusterListener)Adds the given cluster ...
- 部署 YApi 接口管理服务
安装 Node curl -sL https://rpm.nodesource.com/setup_8.x | bash - yum install -y nodejs 安装 MongoDB vi / ...
- 微软新动向之Android和IOS应用 visual studio 2015 Cordova[原创]
自萨蒂亚·纳德拉(Satya Nadella)上任微软CEO以来,可谓是惊喜不断,仿佛让世界尤其是我们.net程序员心中又燃起了希望.先是免费提供 iOS 版和安卓版 Office:然后在 xbox ...
- vue-15-vuex-store的用法
vue-16-vuex 1, 介绍 对 vue 进行状态管理的, 集中存储所有组件的所有状态, 解决多个组件共享数据的问题. 即, 所有组件可以拿到同样的状态, 组件间共享数据 2, 在之前进行数据交 ...
- vue-06-过度和动画
1, css过度与动画 需要使用 v-if, v-show 来进行 1), 过度类名 v-enter: 进入时触发 v-enter-active: 执行过程中 v-enter-to: 停止时进行 v- ...