事务简单用法

文章一: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 事务(转载)的更多相关文章

  1. 分享我们项目中基于EF事务机制的架构 【转载】

    http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html 写在前面: 1. 本文中单元测试 ...

  2. 分享我们项目中基于EF事务机制的架构

    写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...

  3. EF 事务

    http://yanwushu.byethost7.com/?p=87 1. EF对事务进行了封装:context的saveChange()是有事务性的. 2. 依赖多个不同的Context的操作(即 ...

  4. EF 事务(非分布式事务)

    在EF 中怎么使用事务? 这个问题纠结了我好久,直到有人跟我一起讨论,我和同事一起讨论查资料. 查的好多资料都是使用 TransactionScope,用 TransactionScope 可处理分布 ...

  5. EF事务嵌套

    EF中采用的是数据上下文DbContext,当针对数据库的所有操作共用一个数据上下文的时候,会使用同一个连接对象,因此连接打开一次,最后Save的时候关闭连接,避免了频繁的创建连接对象打开关闭,这在一 ...

  6. MySql EF事务using不会自动 Rollback的bug

    EF to MySql一般都是用using最后Commit,一直以为最后没Commit,当using调用Dispose会自动Rollback,没想到这儿有个坑,mysql有个bug并不会Rollbac ...

  7. 第六章 springboot + 事务(转载)

    本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5350106.html 在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. myba ...

  8. 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载

    原文:http://www.ite/topic/122700 9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XA ...

  9. EF事务封装

    public class EFTransaction:ITransaction { DbContextTransaction originalTransaction = null; MyDbConte ...

随机推荐

  1. program--历史故事

  2. python 从基础到入门链接

    机器学习篇: 先看的 简书 木子昭的机器学习三剑客 : https://www.jianshu.com/u/c5d047065c42 然后看完之后又发现一个很好的链接, nkwy2012博主提供了很多 ...

  3. #224 Profile Lookup (for in & if )

    我们有一个对象数组,里面存储着通讯录. 函数 lookUp 有两个预定义参数:firstName值和prop属性 . 函数将会检查通讯录中是否存在一个与传入的 firstName 相同的联系人.如果存 ...

  4. eclipse maven install 报错 jdk rather than jre?

    解决方案:window => Perference => java => install jre => 选中jre => edit => 选择文件夹为jdk的

  5. Centos6.5 安装MYSQL 5.5 -5.6.-5.7 一键yum快速安装 ,初始配置

    Centos6.5 安装MYSQL 5.5 ---5.6---5.7 一键yum快速安装 ,初始配置 第一步:安装mysql-5.5---- 5.6 ---- 5.7的yum源 [root@sv03 ...

  6. 记一个centos分区大小调整过程

    1. 备份 /home 目录 [root@centos ~]# cp -r /home /home_backup 2. 查看目前磁盘使用的情况, 需要将 /dev/mapper/centos-home ...

  7. 【webpack】-- 自动刷新与解析

    前端需要频繁的修改js和样式,且需要根据浏览器的页面效果不断的做调整:而且往往我们的开发目录和本地发布目录不是同一个,修改之后需要发布一下:另外一点就是并不是所有的效果都可以直接双击页面就能看到,我们 ...

  8. 技术干货:实时视频直播首屏耗时400ms内的优化实践

    本文由“逆流的鱼yuiop”原创分享于“何俊林”公众号,感谢作者的无私分享. 1.引言 直播行业的竞争越来越激烈,进过2018年这波洗牌后,已经度过了蛮荒暴力期,剩下的都是在不断追求体验.最近正好在做 ...

  9. Android 代码混淆配置总结

    一.前言 为何需要混淆呢?简单的说,就是将原本正常的项目文件,对其类,方法,字段,重新命名,a,b,c,d,e,f…之类的字母,达到混淆代码的目的,这样反编译出来,结构乱糟糟的,看了也头大. 另外说明 ...

  10. wordpress背景添加跟随鼠标动态线条特效

    今天看到别人的博客,在鼠标移动背景时会出现线条动态特效 感觉挺有意思的,还有另一种,在背景点击时会跳出字符特意去找了方法,以为需要添加代码的,结果只要安装个插件就可以了,所以说wordpress就是方 ...