一. 说明

 EF版本的事务介绍详见:

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

  本节主要介绍EF Core下的三种事务的用法和各自的使用场景,其中SaveChanges和DBContextTransaction事务与EF版本的基本一致,在该章节中补充一些新的使用场景和配置方式,TransactionScope环境事务与EF 版本的有着本质的区别,它目前不支持分布式数据库事务。

  后面章节将继续介绍事务的基础概念、事务的隔离级别和带来的各种问题。

二. 默认事务(SaveChanges)

(1).默认情况下,如果数据库提供程序支持事务,单个 SaveChanges() 调用中的所有变更都会在一个事务中被提交。如果其中任何一个变更失败了, 那么事务就会回滚,没有任何变更会被应用到数据库。这意味着 SaveChanges() 能够确保要么成功保存,要么在发生错误时不对数据库做任何修改。

(2).关闭默认事务:context.Database.AutoTransactionsEnabled = false; 如:Test3()方法,第一条数据保存成功,第二条失败。

 代码分享:

 1         /// <summary>
 2         /// 全部成功
 3         /// </summary>
 4         public static void Test1()
 5         {
 6             using (EFDB01Context db = new EFDB01Context())
 7             {
 8                 db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
 9                 db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员2", addTime = DateTime.Now });
10                 db.SaveChanges();
11             }
12         }
13 
14         /// <summary>
15         /// 全部失败
16         /// </summary>
17         public static void Test2()
18         {
19             using (EFDB01Context db = new EFDB01Context())
20             {
21                 try
22                 {
23                     db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
24                     db.T_RoleInfor.Add(new T_RoleInfor() { id = 123, roleName = "管理员2", addTime = DateTime.Now });
25                     db.SaveChanges();
26                 }
27                 catch (Exception)
28                 {
29                     Console.WriteLine("出错了,两条数据都没有执行成功");
30                 }
31             }
32         }
33 
34         /// <summary>
35         /// 第一条成功,第二条失败
36         /// </summary>
37         public static void Test3()
38         {
39             using (EFDB01Context db = new EFDB01Context())
40             {
41                 try
42                 {
43                     //关闭SaveChanges的默认事务
44                     db.Database.AutoTransactionsEnabled = false;
45 
46                     db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
47                     db.T_RoleInfor.Add(new T_RoleInfor() { id = 123, roleName = "管理员2", addTime = DateTime.Now });
48 
49                     //db.T_UserInfor.Add(new T_UserInfor() { id = Guid.NewGuid().ToString("N"), userName = "管理员1", addTime = DateTime.Now });
50                     //db.T_UserInfor.Add(new T_UserInfor() { id = Guid.NewGuid().ToString("N")+"123", userName = "管理员2", addTime = DateTime.Now });
51 
52                     db.SaveChanges();
53                 }
54                 catch (Exception)
55                 {
56                     Console.WriteLine("出错了,第一条数据插入成功了");
57                 }
58             }
59         }

 

三. DbContextTransaction

1. 使用方式

  BeginTransaction开启事务、Commit提交事务、Rollback回滚事务、Dispose销毁,如果用Using包裹的话,不再需要手动Rollback,走完Using会自动回滚。如果不用Using包裹事务,就需要在Catch中手动RollBack回滚,并且最好最后手动的Dispose一下。(如SameDbContext文件夹中的Test1和Test2方法)

2. 使用场景

 A. 同一个上下文多个SaveChanges的方法(如:自增主键后续要用到,如Test2方法)、SaveChanges和EF调用SQL语句混用(如Test2方法)

 1        /// <summary>
 2         /// 三条添加语句共享同一个事务,最后使用 transaction.Commit() 统一提交,三条全部执行成功,则影响到数据库,
 3         /// 如果任何一个命令失败,则在事务被回收(Dispose)时会自动回滚,对数据库无影响。 
 4         /// </summary>
 5         public static void Test1()
 6         {
 7             using (EFDB01Context db = new EFDB01Context())
 8             {
 9                 using (var transaction = db.Database.BeginTransaction())
10                 {
11                     try
12                     {
13                         db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
14                         db.SaveChanges();
15 
16                         db.T_RoleInfor.Add(new T_RoleInfor() { id = 111, roleName = "管理员2", addTime = DateTime.Now });  //报错
17                         db.SaveChanges();
18 
19                         string sql1 = @"insert into T_RoleInfor (roleName,roleDescription,addTime) values (@roleName,@roleDescription,@addTime)";
20                         SqlParameter[] pars1 ={
21                                                  new SqlParameter("@roleName","管理员3"),
22                                                  new SqlParameter("@roleDescription","txt11"),
23                                                  new SqlParameter("@addTime",DateTime.Now)
24                                             };
25                         db.Database.ExecuteSqlCommand(sql1, pars1);
26                         transaction.Commit();
27 
28                         Console.WriteLine("成功了");
29                     }
30                     catch (Exception)
31                     {
32                         Console.WriteLine("失败了");
33                     }
34                 }
35             }
36         }
37 
38         /// <summary>
39         /// 如果不用Using包裹事务,就需要在Catch中手动RollBack回滚
40         /// </summary>
41         public static void Test2()
42         {
43             using (EFDB01Context db = new EFDB01Context())
44             {
45                 var transaction = db.Database.BeginTransaction();
46                 try
47                 {
48                     var d1 = new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now };
49                     db.T_RoleInfor.Add(d1);
50                     db.SaveChanges();
51 
52                     db.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员2"+d1.id, addTime = DateTime.Now });
53                     db.SaveChanges();
54 
55                     string sql1 = @"insert into T_RoleInfor (roleName,roleDescription,addTime) values (@roleName,@roleDescription,@addTime)";
56                     SqlParameter[] pars1 ={
57                                                  new SqlParameter("@roleName","管理员3"),
58                                                  new SqlParameter("@roleDescription","txt11"),
59                                                  new SqlParameter("@addTime",DateTime.Now)
60                                             };
61                     db.Database.ExecuteSqlCommand(sql1, pars1);
62                     transaction.Commit();
63 
64                     Console.WriteLine("成功了");
65 
66                 }
67                 catch (Exception)
68                 {
69                     transaction.Rollback();
70                     Console.WriteLine("失败了");
71                 }
72                 finally
73                 {
74                     transaction.Dispose();
75                 }
76 
77             }
78         }

 B. 同一个数据库多个上下文但“同一个连接”的事务。其中一个上下文开启事务,另外上下文通过UseTransaction方法来实现共享事务。

 情况①:

  EFDB01Context直接在OnConfiguring中写死连接字符串,多次new上下文,如Test1方法,则是多个连接,不能共享事务。

第五节:EF Core中的三类事务(SaveChanges、DbContextTransaction、TransactionScope)

 1  /// <summary>
 2         /// 情况一:在OnConfiguring中书写连接字符串,创建两个上下文,相当于两个连接,两个连接之间不能通过使用UseTransaction,建立事务连接。
 3         /// 会报下面的错。
 4         /// The specified transaction is not associated with the current connection. Only transactions associated with the current connection may be used.
 5         /// </summary>
 6         public static void Test1()
 7         {
 8             using (EFDB01Context context1 = new EFDB01Context())
 9             {
10                 using (var transaction = context1.Database.BeginTransaction())
11                 {
12                     try
13                     {
14                         context1.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
15                         context1.SaveChanges();
16 
17                         using (EFDB01Context context2 = new EFDB01Context())
18                         {
19                             context2.Database.UseTransaction(transaction.GetDbTransaction());
20 
21                             context1.T_RoleInfor.Add(new T_RoleInfor() { roleName = "管理员1", addTime = DateTime.Now });
22                             context1.SaveChanges();
23                         }
24 
25                         //统一提交
26                         transaction.Commit();
27                         Console.WriteLine("成功了");
28                     }
29                     catch (Exception ex)
30                     {
31                         Console.WriteLine(ex.Message);
32                     }
33                 }
34             }
35 
36 
37         }
View Code

相关文章:

  • 2021-11-08
  • 2021-09-26
  • 2021-11-12
  • 2022-12-23
  • 2021-06-09
  • 2022-12-23
  • 2022-01-04
  • 2021-06-12
猜你喜欢
  • 2021-08-19
  • 2022-12-23
  • 2022-12-23
  • 2021-06-21
  • 2022-12-23
  • 2021-10-03
  • 2022-12-23
相关资源
相似解决方案