第七节: EF的三种事务的应用场景和各自注意的问题(SaveChanges、DBContextTransaction、TransactionScope)

一. 什么是事务

   我们通俗的理解事务就是一系列操作要么全部成功、要么全部失败(不可能存在部分成功,部分失败的情况)。

   举一个事务在我们日常生活中的经典例子:两张银行卡(甲、乙),甲向乙转钱,整个过程需要执行两个操作,甲账户钱减少,乙账户钱增加,这是转账成功的情况;转账失败时候,二者均不执行,甲乙账户钱都不变。

1. SQLServer中的事务

  SQLServer中的事务具体封装方式有多种,但无论是哪种,都需要依赖于这三句代码:begin transaction 、commit transaction、rollback transaction。 

   具体怎么使用,详见数据库事务章节:去复习

2. EF中的事务

   EF中的事务主要分为三类,分别是SaveChanges、DbContextTransaction、TransactionScope。

   需要掌握的是这三种事务各自的使用方式和适用场景。

二. SaveChanges

   SaveChanges是EF中最常见的事务了,在前面章节,多次提到,SaveChanges一次性将本地缓存中所有的状态变化一次性提交到数据库,这就是一个事务,要么统一成功,要么统一回滚。

   应用场景:该种事务模式在实际开发中非常常用,在处理模块业务同时需要对一张表(或多张表)进行一系列增删改操作,但这些操作都是要么都成功,要么都失败,这种情况下可以在流程的最后 调用SaveChanges,一次性保存本地属性状态的全部变化。

  该模式作用于一个DBContext,即一个数据库的EF的上下文,不能控制多个数据库。

    比如:注册场景,可能需要向用户表、日志表、账户表等多张表中插入数据,其中一张表插入失败,所有的都需要回滚,这种情况,就可以在该业务的最后,统一调用SaveChanges一次性的事务提交。

1. 事务成功

复制代码

 1      private static void TestSaveChanges()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 //增加6                 TestInfor t1 = new TestInfor()7                 {8                     id = Guid.NewGuid().ToString("N"),9                     txt1 = "txt1",
10                     txt2 = "txt2"
11                 };
12                 db.Set<TestInfor>().Add(t1);
13                 //删除
14                 TestInfor t2 = db.Set<TestInfor>().Where(u => u.id == "1").FirstOrDefault();
15                 if (t2 != null)
16                 {
17                     db.Set<TestInfor>().Remove(t2);
18                 }
19                 //修改
20                 TestInfor t3 = db.Set<TestInfor>().Where(u => u.id == "3").FirstOrDefault();
21                 t3.txt2 = "我是李马茹23";
22 
23                 //SaveChanges事务提交
24                 int n = db.SaveChanges();
25                 Console.WriteLine("数据作用条数:" + n);
26             }
27         }    

复制代码

2. 事务回滚

复制代码

 1       private static void TestSaveChangesFailure()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 //增加6                 TestInfor t1 = new TestInfor()7                 {8                     id = Guid.NewGuid().ToString("N"),9                     txt1 = "txt1",
10                     txt2 = "txt2"
11                 };
12                 db.Set<TestInfor>().Add(t1);
13                 //删除
14                 TestInfor t2 = db.Set<TestInfor>().Where(u => u.id == "1").FirstOrDefault();
15                 if (t2 != null)
16                 {
17                     db.Set<TestInfor>().Remove(t2);
18                 }
19                 //修改
20                 TestInfor t3 = db.Set<TestInfor>().Where(u => u.id == "3").FirstOrDefault();
21                 t3.txt2 = "我是李马茹23";
22                 //增加(制造错误)
23                 TestInfor t4 = new TestInfor()
24                 {
25                     id = Guid.NewGuid().ToString("N") + "123",
26                     txt1 = "txt1",
27                     txt2 = "txt2"
28                 };
29                 db.Set<TestInfor>().Add(t4);
30 
31                 //SaveChanges事务提交
32                 int n = db.SaveChanges();
33                 Console.WriteLine("数据作用条数:" + n);
34             }
35         }

复制代码

三. DbContextTransaction事务

  该事务为EF6新增的事务,通常用于手动接管事务,某些操作是一个事务,某些操作是另外一个事务。

  使用场景:EF调用SQL语句的时候使用该事务、 多个SaveChanges的情况(解决自增ID另一个业务中使用的场景)。

  核心代码:BeginTransaction、Commit、Rollback、Dispose. 如果放到using块中,就不需要手动Dispose了。

  该种事务与数据库中的transaction事务原理一致,在EF中,由于每次调用 db.Database.ExecuteSqlCommand(sql1, pars1)的时候,即刻执行了该SQL语句,所以要把他放到一个大的事务中,整体提交、回滚.(EF6新增的)

1. 事务成功

复制代码

 1      private static void TestDbContextTransaction()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 DbContextTransaction trans = null;6                 try7                 {8                     //开启事务9                     trans = db.Database.BeginTransaction();
10                     //增加
11                     string sql1 = @"insert into TestInfor  values(@id,@txt1,@txt2)";
12                     SqlParameter[] pars1 ={
13                                                  new SqlParameter("@id",Guid.NewGuid().ToString("N")),
14                                                  new SqlParameter("@txt1","txt11"),
15                                                  new SqlParameter("@txt2","txt22")
16                                             };
17                     db.Database.ExecuteSqlCommand(sql1, pars1);
18                     //删除
19                     string sql2 = @"delete from TestInfor where id=@id";
20                     SqlParameter[] pars2 ={
21                                                  new SqlParameter("@id","22")
22                                             };
23                     db.Database.ExecuteSqlCommand(sql2, pars2);
24                     //修改
25                     string sql3 = @"update TestInfor set txt1=@txt1 where id=@id";
26                     SqlParameter[] pars3 ={
27                                                  new SqlParameter("@id","3"),
28                                                  new SqlParameter("@txt1","二狗子")
29                                             };
30                     db.Database.ExecuteSqlCommand(sql3, pars3);
31 
32                     //提交事务
33                     trans.Commit();
34                     Console.WriteLine("事务成功了");
35                 }
36                 catch (Exception ex)
37                 {
38                     Console.WriteLine(ex.Message);
39                     trans.Rollback();
40 
41                 }
42                 finally
43                 {
44                     trans.Dispose();     //也可以把该事务写到using块中,让其自己托管,就不需要手动释放了
45                 }
46             }
47         }

复制代码

2. 事务回滚

复制代码

 1      private static void TestDbContextTransactionFailure()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 DbContextTransaction trans = null;6                 try7                 {8                     //开启事务9                     trans = db.Database.BeginTransaction();
10                     //增加
11                     string sql1 = @"insert into TestInfor  values(@id,@txt1,@txt2)";
12                     SqlParameter[] pars1 ={
13                                                  new SqlParameter("@id",Guid.NewGuid().ToString("N")),
14                                                  new SqlParameter("@txt1","txt11"),
15                                                  new SqlParameter("@txt2","txt22")
16                                             };
17                     db.Database.ExecuteSqlCommand(sql1, pars1);
18                     //删除
19                     string sql2 = @"delete from TestInfor where id=@id";
20                     SqlParameter[] pars2 ={
21                                                  new SqlParameter("@id","22")
22                                             };
23                     db.Database.ExecuteSqlCommand(sql2, pars2);
24                     //修改
25                     string sql3 = @"update TestInfor set txt1=@txt1 where id=@id";
26                     SqlParameter[] pars3 ={
27                                                  new SqlParameter("@id","3"),
28                                                  new SqlParameter("@txt1","二狗子222")
29                                             };
30                     db.Database.ExecuteSqlCommand(sql3, pars3);
31 
32 
33                     //增加(制造错误)
34                     string sql4 = @"insert into TestInfor  values(@id,@txt1,@txt2)";
35                     SqlParameter[] pars4 ={
36                                                  new SqlParameter("@id",Guid.NewGuid().ToString("N")+"123"),
37                                                  new SqlParameter("@txt1","txt11"),
38                                                  new SqlParameter("@txt2","txt22")
39                                             };
40                     db.Database.ExecuteSqlCommand(sql4, pars4);
41 
42                     //提交事务
43                     trans.Commit();
44                     Console.WriteLine("事务成功了");
45                 }
46                 catch (Exception ex)
47                 {
48                     Console.WriteLine(ex.Message);
49                     trans.Rollback();
50 
51                 }
52                 finally
53                 {
54                     trans.Dispose();
55                 }
56             }
57         }

复制代码

3. 自DbContextTransaction事务测试多个SaveChanges的情况统一回滚

复制代码

 1   private static void DbContextTransSaveChanges()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 //自动脱管,不需要手动释放6                 using (DbContextTransaction trans = db.Database.BeginTransaction())7                 {8                     try9                     {
10                         TestInfor t1 = new TestInfor()
11                         {
12                             id = Guid.NewGuid().ToString("N"),
13                             txt1 = "111111111",
14                             txt2 = "222222222222"
15                         };
16                         db.Entry(t1).State = EntityState.Added;
17                         db.SaveChanges();
18 
19                         //人为制造失败情况
20                         TestInfor t2 = new TestInfor()
21                         {
22                             id = Guid.NewGuid().ToString("N") + "123",
23                             txt1 = "111111111",
24                             txt2 = "222222222222"
25                         };
26                         db.Entry(t2).State = EntityState.Added;
27                         db.SaveChanges();
28 
29                         trans.Commit();
30                     }
31                     catch (Exception)
32                     {
33                         trans.Rollback();
34                     }
35 
36                 }
37             }
38         }

复制代码

四. TransactionScope事务

1. 该事务用来处理多个SaveChanges的事务(特殊情况的业务)或者多个DBContext(每个DBContext是一个实例,代表不同的数据库连接).

2. 核心代码:(一个Complete函数走天下,异常的话,自动回滚 ,也可以结合try-catch Transaction.Current.Rollback();实现回滚)

         需要引入程序集:using System.Transactions;

3. 适用场景:

  ①该种事务适用于多数据库连接的情况

  特别注意:如果使用该事务来处理多个数据库(多个DBContex)时,必须手动开启msdtc服务,这样才可以将多个DB的SaveChange给放到一个事务中,如果失败, 则多个数据库的数据统一回滚.

     开启msdtc服务的步骤: cmd命令→net start msdtc

    ②主键id自增的情况,同一个业务线中,需要拿到新增加的数据的主键id,进行操作。

      ③多线程带锁的情况,同一条业务线前半部分必须先SaveChanges,才能保证数据准确性(测试简单版本,实际的业务场景待补充!!!)

4. 主键自增被使用的情况的解决方案

复制代码

 1     private static void Test3()2         {3             using (DbContext db = new CodeFirstModel())4             {5                 using (TransactionScope trans = new TransactionScope())6                 {7                     try8                     {9                         TestInfor2 t1 = new TestInfor2()
10                         {
11                             txt11 = Guid.NewGuid().ToString("N"),
12                             txt22 = Guid.NewGuid().ToString("N")
13                         };
14                         db.Set<TestInfor2>().Add(t1);
15                         //如果这里不写SaveChanges的话,t1.id永远为0
16                         db.SaveChanges();
17 
18 
19                         TestInfor2 t2 = new TestInfor2()
20                         {
21                             txt11 = (t1.id + 1).ToString(),
22                             txt22 = Guid.NewGuid().ToString("N")
23                         };
24                         db.Entry(t2).State = EntityState.Added;
25                         db.SaveChanges();
26 
27                         //事务统一提交(若失败则统一回滚)
28                         trans.Complete();
29                         Console.WriteLine("自增提交成功");
30                     }
31                     catch (Exception)
32                     {
33                         Transaction.Current.Rollback();
34                     }
35                 }    
36             }
37         }

复制代码

5. 多个DBContext、多个数据库的情况。

复制代码

 1  private static void TransactionScopeTwoDB()2         {3             using (TransactionScope trans = new TransactionScope())4             {5                 try6                 {7                     DbContext db1 = new CodeFirstModel();8                     DbContext db2 = new CodeFirstModel2();9                     //数据库1
10                     TestInfor t1 = new TestInfor()
11                     {
12                         id = Guid.NewGuid().ToString("N"),
13                         txt1 = "111111111",
14                         txt2 = "222222222222"
15                     };
16                     db1.Entry(t1).State = EntityState.Added;
17                     db1.SaveChanges();
18 
19                     //数据库2
20                     TestOne t2 = new TestOne()
21                     {
22                         id = Guid.NewGuid().ToString("N"),    //可以在此处手动制造个错误,来测试多数据库的回滚问题
23                         t1 = "222",
24                         t2 = "2222"
25                     };
26                     db2.Entry(t2).State = EntityState.Added;
27                     db2.SaveChanges();
28 
29                     trans.Complete();
30                     Console.WriteLine("多个数据库添加成功");
31                 }
32                 catch (Exception)
33                 {
34                     Transaction.Current.Rollback();
35                 }
36 
37             }
38         }

复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux怎么检测文件完整性,Linux如何基于AIDE检测文件系统完整性

一、AIDEAIDE(Advanced Intrusion Detection Environment)是一款针对文件和目录进行完整性对比检查的程序&#xff0c;它被开发成Tripwire的一个替代品。AIDE如何工作AIDE通过构造指定文件的完整性样本库(快照)&#xff0c;作为比对标准&#xff0c;当这些文件发生改动时&#…

第八节: EF的性能篇(一) 之 EF自有方法的性能测试

一. 开发中常见的性能问题 我们在日常开发过程中&#xff0c;由于一些不好的习惯&#xff0c;经常会导致所写的代码性能低下&#xff0c;却毫无发觉&#xff0c;下面就总结一下常见的一些性能问题。 1. 真假分页 ① 假分页&#xff1a; db.xxx.toList().Skip(2).take(4) 。 ②…

linux 中将文件设置密码,linux – 如何使用公钥在openssl中加密大文件

如何使用公钥加密大文件&#xff0c;以便没有人除了拥有私钥的人能够解密&#xff1f;我可以使RSA公钥和私钥&#xff0c;但当涉及到使用此命令加密大文件&#xff1a;openssl rsautl -encrypt -pubin -inkey public.pem -in myLargeFile.xml -out myLargeFile_encrypted.xml和…

如何查看自己linux版本,如何查看Linux操作系统版本?

1. 查看内核版本命令$ cat /proc/versionLinux version 2.6.32-358.el6.x86_64 (mockbuildc6b8.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Fri Feb 22 00:31:26 UTC 2013$ uname -aLinux 192.168.1.10 2.6.32-358.el6.x86_64 #1 SMP…

第九节: EF的性能篇(二) 之 Z.EntityFramework.Extensions程序集解决EF的性能问题

一. 综述 该模块主要介绍&#xff1a;EF的性能优化插件Z.EntityFramework.Extensions&#xff0c;该插件收费。 (一). 简介 1. 相关网站&#xff1a;http://www.zzzprojects.com/ 2. 下载途径&#xff1a;通过Nuget直接下载或者去官网下载(要注意更新最新版本&#xff0c;可…

linux ssh非交互脚本,sshpass实现shell脚本非交互密码验证

1、sshpass的简介OpenSSH 自带的 ssh 客户端程序&#xff0c;默认不允许以非交互的方式传递密码&#xff0c;所以需要远程登录服务器进行批处理就无法进行。sshpass 的出现&#xff0c;解决了这一问题。它允许你用 -p 参数指定明文密码&#xff0c;然后直接登录远程服务器。2、…

第十节: EF的三种追踪实体状态变化方式(DBEntityEntry、ChangeTracker、Local)

一. 简介 我们在前面章节介绍EF基本增删改的时候&#xff0c;曾说过EF的SaveChanges()方法&#xff0c;会一次性的将所有的实体的状态变化统一提交到数据库&#xff0c;那么你是否想过EF的实体会有哪些状态变化呢&#xff1f;什么原因会导致其变化呢&#xff1f;我们怎么来追踪…

mathematica在linux上运行,Mathematica在Ubuntu中的表现及修正

Mathematica在Ubuntu中的表现及修正发布时间:2008-03-11 16:13:58来源:红联作者:verytow在Ubuntu-feisy中&#xff0c;使用Mathematica有一段时间了&#xff0c;由于Linux系统内存管理机制的优越性(具体的&#xff0c;我得去查资料&#xff0c;只是据说&#xff1b;用于计算大型…

第十一节: EF的三种模式(一) 之 DBFirst模式(SQLServer和MySQL两套方案)

一. 简介 EF连接数据库有三种模式&#xff0c;分别是DBFirst、ModelFirst、CodeFirst&#xff0c;分别适用于不同的开发场景。 该章节&#xff0c;将主要介绍EF的DBFirst连接SQLServer数据库和MySql数据库两种操作方式 该模式在EF中出现的出现的最早&#xff0c;符合我们的传统…

linux禁止u盘自动运行,求设置U盘自动运行和禁止运行的方法。

方法一&#xff1a;这种方法比较简单&#xff0c;就是用户在放入U盘同时&#xff0c;按住Shift键直至U盘的指示灯熄灭&#xff0c;然后松开Shift键即可。这种方法是一种临时应急法&#xff0c;如果拥护之是偶尔项禁止自动播放功能&#xff0c;这种方法比较合适。方法二&#xf…

第十二节: EF的三种模式(二) 之 ModelFirst模式(SQLServer为例)

一. 简介 顾名思义&#xff0c;ModelFirst是模型优先&#xff0c;是DBFirst的逆向模式&#xff0c;先建立实体数据模型&#xff0c;然后根据实体数据模型来生成数据库&#xff0c;从而驱动整个开发流程.&#xff08;生成一个空的edmx文件&#xff0c;手动在里面建立实体模型&am…

linux 查看zookeepr所在路径,Linux系统:Centos7下搭建ZooKeeper3.4中间件,常用命令总结...

本文源码&#xff1a;[GitHub点这里](https://github.com/cicadasmile/linux-system-base) || [GitEE点这里](https://gitee.com/cicadasmile/linux-system-base)# 一、下载解压##1、Zookeeper简介Zookeeper 作为一个分布式的服务框架&#xff0c;主要用来解决分布式集群中应用…

第十三节: EF的三种模式(三) 之 来自数据库的CodeFirst模式

一. 简介 【来自数据库的Code First模式】实质上并不是CodeFirst模式&#xff0c;而是DBFirst模式的轻量级版本&#xff0c;在该模式中取消了edmx模型和T4模板&#xff0c;直接生成了EF上下文和相应的类&#xff0c;该模式出现在VS2015版本以后。 该模式也是适用于数据库已经设…

第十四节: EF的三种模式(四) 之 原生正宗的 CodeFirst模式的默认约定

一. 简介 1. 正宗的CodeFirst模式是不含有edmx模型&#xff0c;需要手动创建实体、创建EF上下文&#xff0c;然后生成通过代码来自动映射生成数据库。 2. 旨在&#xff1a;忘记SQL、忘记数据库。 3. 三类配置&#xff1a;One To One(one-to-zero-or-one)、One To Many、Many To…

查看linux硬核上的线程,给大家分享一点基础硬核知识哦 Linux的基础指令操作Lin...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼给大家分享一点基础硬核知识哦Linux的基础指令操作Linux的基础指令操作Linux的指令下达方式很简单&#xff0c;只需要记得几个重要的概念就可以l: command&#xff1a;指令&#xff0c;一行指令中第一个输入的部分绝对是指令2&…

第十五节: EF的CodeFirst模式通过DataAnnotations修改默认协定

一. 简介 1. DataAnnotations说明&#xff1a;EF提供以特性的方式添加到 domain classes上,其中包括两类&#xff1a; A&#xff1a;System.ComponentModel.DataAnnotations命名空间下的特性是表中列的属性的。 包括&#xff1a;Key、Required、MinLength和MaxLength、StringL…

linux 性能测试iostat,Linux性能分析之二(iostat)

前言在之前的博客中我们详细的说明了性能瓶颈的解决思路&#xff0c;也详细介绍了Vmstat的使用&#xff0c;今天我们就详细说说磁盘IO的那些事&#xff0c;磁盘IO是我们最常遇到的瓶颈&#xff0c;下面我们根据iostat详细聊聊磁盘IO一、磁盘IO性能指标1.1、每秒IO数(tps)对于磁…

第十六节: EF的CodeFirst模式通过Fluent API修改默认协定

一. 简介 1. 优先级&#xff1a;Fluent API > data annotations > default conventions. 2. 所有的Fluent API配置都要在 OnModelCreating这个重写方法中进行 3. 常见的配置&#xff1a; ① 获取表对应的配置根&#xff1a; var stu modelBuilder.Entity<XXX>(); ②…

安卓手机挂载Linux,android 挂载NFS教程

0&#xff0c;在Ubuntu新建nfs目录:#mkdir /home/shuimu/arm_project/rootfs将FORLINX_6410_yaffs2_v1.0.tgz复制到rootfs中&#xff0c;解压当前文件夹#tar–zxf FORLINX_6410_yaffs2_v1.0.tgz1.烧写mmc&#xff0c;uboot&#xff0c;zImage到开发板。2&#xff0c;在ubuntu上…

linux apache jk,Linux下Apache+Tomcat+JK实现负载均衡和群集的完整过程

感谢chaijunkun的精彩大作&#xff0c;真的辛苦了。最近在开发的项目需要承受很高的并发量。综合各种情况&#xff0c;决定使用ApacheTomcatJK的方式实现负载均衡&#xff0c;并且作为一个统一的服务还要实现群集(同步Session)。在网上找了很多资料&#xff0c;都是零零散散的&…