使用事务Working with Transactions

10/23/2016

本文内容

备注

仅限 EF6 及更高版本 - 此页面中讨论的功能、API 等已引入实体框架 6。EF6 Onwards Only - The features, APIs, etc. discussed in this page were introduced in Entity Framework 6. 如果使用的是早期版本,则部分或全部信息不适用。If you are using an earlier version, some or all of the information does not apply.

本文档介绍如何在 EF6 中使用事务,包括自 EF5 后添加的增强功能,以便轻松处理事务。This document will describe using transactions in EF6 including the enhancements we have added since EF5 to make working with transactions easy.

默认情况下,什么是 EFWhat EF does by default

在所有版本的实体框架中,每当你执行 **SaveChanges ( # B1 ** 以便在数据库上执行插入、更新或删除操作时,框架会将该操作包装在事务中。In all versions of Entity Framework, whenever you execute SaveChanges() to insert, update or delete on the database the framework will wrap that operation in a transaction. 此事务只持续足够长的时间来执行操作,然后完成。This transaction lasts only long enough to execute the operation and then completes. 执行另一个这样的操作时,将启动新事务。When you execute another such operation a new transaction is started.

默认情况下,从 EF6 **Database.ExecuteSqlCommand ( # B1 ** 默认情况下会在事务中包装命令(如果尚未存在)。Starting with EF6 Database.ExecuteSqlCommand() by default will wrap the command in a transaction if one was not already present. 此方法有一些重载,允许你根据需要重写此行为。There are overloads of this method that allow you to override this behavior if you wish. 此外,在 EF6 中通过 Api 包括在模型中的存储过程(如 **ObjectContext.ExecuteFunction ( # B1 ** )执行相同 (,只不过默认行为不能在) 重写。Also in EF6 execution of stored procedures included in the model through APIs such as ObjectContext.ExecuteFunction() does the same (except that the default behavior cannot at the moment be overridden).

在任一情况下,事务的隔离级别都是数据库提供程序认为其默认设置的任何隔离级别。In either case, the isolation level of the transaction is whatever isolation level the database provider considers its default setting. 例如,默认情况下,在 SQL Server 此为 "已提交读"。By default, for instance, on SQL Server this is READ COMMITTED.

实体框架不会在事务中包装查询。Entity Framework does not wrap queries in a transaction.

此默认功能适用于很多用户,如果没有,则无需在 EF6 中执行任何其他操作;只需像往常一样编写代码。This default functionality is suitable for a lot of users and if so there is no need to do anything different in EF6; just write the code as you always did.

但是,某些用户需要更好地控制其事务–以下各节将对此进行介绍。However some users require greater control over their transactions – this is covered in the following sections.

Api 的工作原理How the APIs work

在实体框架 EF6 之前,在打开数据库连接自身之前 (会引发异常,如果传递的连接已) 打开。Prior to EF6 Entity Framework insisted on opening the database connection itself (it threw an exception if it was passed a connection that was already open). 由于只能在打开的连接上启动事务,这意味着用户可以将多个操作包装到一个事务中的唯一方法是使用TransactionScope或使用ObjectContext属性,并开始直接对返回的EntityConnection对象调用open ( # B1和BeginTransaction ( # B3 。Since a transaction can only be started on an open connection, this meant that the only way a user could wrap several operations into one transaction was either to use a TransactionScope or use the ObjectContext.Connection property and start calling Open() and BeginTransaction() directly on the returned EntityConnection object. 此外,如果你在基础数据库连接上自行启动了事务,则与数据库联系的 API 调用将失败。In addition, API calls which contacted the database would fail if you had started a transaction on the underlying database connection on your own.

备注

实体框架6中删除了仅接受关闭的连接的限制。The limitation of only accepting closed connections was removed in Entity Framework 6. 有关详细信息,请参阅 连接管理。

从 EF6 开始,框架现在提供:Starting with EF6 the framework now provides:

**BeginTransaction ( # B1 ** :用户可以更轻松地在现有 DbContext 中启动和完成事务,并允许多个操作合并到同一个事务中,并因此全部提交或全部回滚。Database.BeginTransaction() : An easier method for a user to start and complete transactions themselves within an existing DbContext – allowing several operations to be combined within the same transaction and hence either all committed or all rolled back as one. 它还允许用户更轻松地指定事务的隔离级别。It also allows the user to more easily specify the isolation level for the transaction.

**UseTransaction ( # B1 ** :这允许 DbContext 使用在实体框架之外启动的事务。Database.UseTransaction() : which allows the DbContext to use a transaction which was started outside of the Entity Framework.

将多个操作合并为同一上下文中的一个事务Combining several operations into one transaction within the same context

**BeginTransaction ( # B1 ** 具有两个替代,其中一个将使用显式 IsolationLevel ,另一个不采用任何参数,并从基础数据库提供程序使用默认的 IsolationLevel。Database.BeginTransaction() has two overrides – one which takes an explicit IsolationLevel and one which takes no arguments and uses the default IsolationLevel from the underlying database provider. 这两个替代都返回一个 处理 对象,该对象提供 ** ( # B1 ** 和 **rollback ( # B3 ** 方法,在基础存储事务上执行提交和回滚。Both overrides return a DbContextTransaction object which provides Commit() and Rollback() methods which perform commit and rollback on the underlying store transaction.

处理在提交或回滚后会被释放。The DbContextTransaction is meant to be disposed once it has been committed or rolled back. 实现此目的的一种简单方法是 使用 ( ... ) {...}One easy way to accomplish this is the using(…) {…} 当 using 块完成时,将自动调用 **Dispose ( # B1 ** 的语法:syntax which will automatically call Dispose() when the using block completes:

using System;

using System.Collections.Generic;

using System.Data.Entity;

using System.Data.SqlClient;

using System.Linq;

using System.Transactions;

namespace TransactionsExamples

{

class TransactionsExample

{

static void StartOwnTransactionWithinContext()

{

using (var context = new BloggingContext())

{

using (var dbContextTransaction = context.Database.BeginTransaction())

{

context.Database.ExecuteSqlCommand(

@"UPDATE Blogs SET Rating = 5" +

" WHERE Name LIKE '%Entity Framework%'"

);

var query = context.Posts.Where(p => p.Blog.Rating >= 5);

foreach (var post in query)

{

post.Title += "[Cool Blog]";

}

context.SaveChanges();

dbContextTransaction.Commit();

}

}

}

}

}

备注

开始事务要求基础存储连接处于打开状态。Beginning a transaction requires that the underlying store connection is open. 因此调用 BeginTransaction ( # A1 将打开连接(如果尚未打开)。So calling Database.BeginTransaction() will open the connection if it is not already opened. 如果处理打开了连接,则在调用 Dispose ( # A1 时将关闭该连接。If DbContextTransaction opened the connection then it will close it when Dispose() is called.

将现有事务传递到上下文Passing an existing transaction to the context

有时,您想要在范围内更广泛的事务,其中包括对同一数据库的操作,而不是在 EF 的外部。Sometimes you would like a transaction which is even broader in scope and which includes operations on the same database but outside of EF completely. 若要实现此目的,您必须打开连接并自行启动事务,然后告诉 EF a) 使用已打开的数据库连接,而 b) 在该连接上使用现有事务。To accomplish this you must open the connection and start the transaction yourself and then tell EF a) to use the already-opened database connection, and b) to use the existing transaction on that connection.

若要执行此操作,必须在上下文类中定义和使用一个构造函数,该构造函数继承自 DbContext 构造函数,该构造函数将使用我) 现有的连接参数,并) contextOwnsConnection 的布尔值。To do this you must define and use a constructor on your context class which inherits from one of the DbContext constructors which take i) an existing connection parameter and ii) the contextOwnsConnection boolean.

备注

在这种情况下,contextOwnsConnection 标志必须设置为 false。The contextOwnsConnection flag must be set to false when called in this scenario. 这一点很重要,因为它会通知实体框架它不应在完成后关闭连接 (例如,请参阅下面的第4行) :This is important as it informs Entity Framework that it should not close the connection when it is done with it (for example, see line 4 below):

using (var conn = new SqlConnection("..."))

{

conn.Open();

using (var context = new BloggingContext(conn, contextOwnsConnection: false))

{

}

}

此外,如果想要避免默认设置) 并让实体框架知道已在连接上启动了现有事务,则必须自行启动该事务 (包括 IsolationLevel (参阅) 下面第33行。Furthermore, you must start the transaction yourself (including the IsolationLevel if you want to avoid the default setting) and let Entity Framework know that there is an existing transaction already started on the connection (see line 33 below).

然后,可以随意直接在 SqlConnection 本身或 DbContext 上执行数据库操作。Then you are free to execute database operations either directly on the SqlConnection itself, or on the DbContext. 所有此类操作在一个事务内执行。All such operations are executed within one transaction. 你需要负责提交或回滚事务,并为其调用 Dispose ( # A1,还负责关闭并释放数据库连接。You take responsibility for committing or rolling back the transaction and for calling Dispose() on it, as well as for closing and disposing the database connection. 例如:For example:

using System;

using System.Collections.Generic;

using System.Data.Entity;

using System.Data.SqlClient;

using System.Linq;

using System.Transactions;

namespace TransactionsExamples

{

class TransactionsExample

{

static void UsingExternalTransaction()

{

using (var conn = new SqlConnection("..."))

{

conn.Open();

using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.Snapshot))

{

var sqlCommand = new SqlCommand();

sqlCommand.Connection = conn;

sqlCommand.Transaction = sqlTxn;

sqlCommand.CommandText =

@"UPDATE Blogs SET Rating = 5" +

" WHERE Name LIKE '%Entity Framework%'";

sqlCommand.ExecuteNonQuery();

using (var context =

new BloggingContext(conn, contextOwnsConnection: false))

{

context.Database.UseTransaction(sqlTxn);

var query = context.Posts.Where(p => p.Blog.Rating >= 5);

foreach (var post in query)

{

post.Title += "[Cool Blog]";

}

context.SaveChanges();

}

sqlTxn.Commit();

}

}

}

}

}

清除事务Clearing up the transaction

可以将 null 传递到 UseTransaction ( # A1,以清除实体框架对当前事务的了解。You can pass null to Database.UseTransaction() to clear Entity Framework’s knowledge of the current transaction. 当你执行此操作时,实体框架不会提交或回滚现有事务,因此请谨慎使用,仅在你确定要执行的操作时使用。Entity Framework will neither commit nor rollback the existing transaction when you do this, so use with care and only if you’re sure this is what you want to do.

UseTransaction 中的错误Errors in UseTransaction

如果在以下情况传递事务,则会在 UseTransaction ( # A1 中看到异常:You will see an exception from Database.UseTransaction() if you pass a transaction when:

实体框架已有一个现有的事务Entity Framework already has an existing transaction

实体框架已在某一 TransactionScope 内运行Entity Framework is already operating within a TransactionScope

传递的事务中的连接对象为 null。The connection object in the transaction passed is null. 也就是说,事务与连接无关-通常是该事务已完成的符号That is, the transaction is not associated with a connection – usually this is a sign that that transaction has already completed

传递的事务中的连接对象与实体框架的连接不匹配。The connection object in the transaction passed does not match the Entity Framework’s connection.

将事务与其他功能一起使用Using transactions with other features

本部分详细说明了上述事务与的交互方式:This section details how the above transactions interact with:

连接复原Connection resiliency

异步方法Asynchronous methods

TransactionScope 交易TransactionScope transactions

连接复原Connection Resiliency

新的连接复原功能不适用于用户启动的事务。The new Connection Resiliency feature does not work with user-initiated transactions. 有关详细信息,请参阅 重试执行策略。

异步编程Asynchronous Programming

前面几节中所述的方法不需要更多选项或设置即可使用 异步查询和保存方法。The approach outlined in the previous sections needs no further options or settings to work with the asynchronous query and save methods. 但请注意,根据您在异步方法中所执行的操作,这可能会导致长时间运行的事务,进而导致死锁或阻塞,导致整个应用程序的性能不佳。But be aware that, depending on what you do within the asynchronous methods, this may result in long-running transactions – which can in turn cause deadlocks or blocking which is bad for the performance of the overall application.

TransactionScope 交易TransactionScope Transactions

在 EF6 之前,提供更大范围事务的建议方法是使用 TransactionScope 对象:Prior to EF6 the recommended way of providing larger scope transactions was to use a TransactionScope object:

using System.Collections.Generic;

using System.Data.Entity;

using System.Data.SqlClient;

using System.Linq;

using System.Transactions;

namespace TransactionsExamples

{

class TransactionsExample

{

static void UsingTransactionScope()

{

using (var scope = new TransactionScope(TransactionScopeOption.Required))

{

using (var conn = new SqlConnection("..."))

{

conn.Open();

var sqlCommand = new SqlCommand();

sqlCommand.Connection = conn;

sqlCommand.CommandText =

@"UPDATE Blogs SET Rating = 5" +

" WHERE Name LIKE '%Entity Framework%'";

sqlCommand.ExecuteNonQuery();

using (var context =

new BloggingContext(conn, contextOwnsConnection: false))

{

var query = context.Posts.Where(p => p.Blog.Rating > 5);

foreach (var post in query)

{

post.Title += "[Cool Blog]";

}

context.SaveChanges();

}

}

scope.Complete();

}

}

}

}

SqlConnection 和实体框架都使用环境 TransactionScope 事务,因此一起提交。The SqlConnection and Entity Framework would both use the ambient TransactionScope transaction and hence be committed together.

从 .NET 4.5.1 TransactionScope 开始,还更新为通过使用 TransactionScopeAsyncFlowOption 枚举来处理异步方法:Starting with .NET 4.5.1 TransactionScope has been updated to also work with asynchronous methods via the use of the TransactionScopeAsyncFlowOption enumeration:

using System.Collections.Generic;

using System.Data.Entity;

using System.Data.SqlClient;

using System.Linq;

using System.Transactions;

namespace TransactionsExamples

{

class TransactionsExample

{

public static void AsyncTransactionScope()

{

using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))

{

using (var conn = new SqlConnection("..."))

{

await conn.OpenAsync();

var sqlCommand = new SqlCommand();

sqlCommand.Connection = conn;

sqlCommand.CommandText =

@"UPDATE Blogs SET Rating = 5" +

" WHERE Name LIKE '%Entity Framework%'";

await sqlCommand.ExecuteNonQueryAsync();

using (var context = new BloggingContext(conn, contextOwnsConnection: false))

{

var query = context.Posts.Where(p => p.Blog.Rating > 5);

foreach (var post in query)

{

post.Title += "[Cool Blog]";

}

await context.SaveChangesAsync();

}

}

}

}

}

}

对于 TransactionScope 方法仍有一些限制:There are still some limitations to the TransactionScope approach:

需要 .NET 4.5.1 或更高版本才能使用异步方法。Requires .NET 4.5.1 or greater to work with asynchronous methods.

除非你确定有且只有一个连接 (云方案不支持分布式事务) ,否则不能用于云方案。It cannot be used in cloud scenarios unless you are sure you have one and only one connection (cloud scenarios do not support distributed transactions).

它不能与 UseTransaction ( # A1 方法结合前面的部分。It cannot be combined with the Database.UseTransaction() approach of the previous sections.

如果你颁发了任何 DDL 并且尚未通过 MSDTC 服务启用分布式事务,则它会引发异常。It will throw exceptions if you issue any DDL and have not enabled distributed transactions through the MSDTC Service.

TransactionScope 方法的优点:Advantages of the TransactionScope approach:

如果与同一事务中的另一个数据库建立了多个连接,则它会自动将本地事务升级到分布式事务,或将与一个数据库的连接组合到同一个事务中的不同数据库 (注意:您必须将 MSDTC 服务配置为允许此工作) 的分布式事务。It will automatically upgrade a local transaction to a distributed transaction if you make more than one connection to a given database or combine a connection to one database with a connection to a different database within the same transaction (note: you must have the MSDTC service configured to allow distributed transactions for this to work).

易于编码。Ease of coding. 如果你更愿意在后台隐式处理事务,而不是显式地在控制下进行处理,则 TransactionScope 方法可能更适合你。If you prefer the transaction to be ambient and dealt with implicitly in the background rather than explicitly under you control then the TransactionScope approach may suit you better.

总之,在上面的 BeginTransaction ( # A1 和 UseTransaction ( # A3 Api 中,大多数用户不再需要 TransactionScope 方法。In summary, with the new Database.BeginTransaction() and Database.UseTransaction() APIs above, the TransactionScope approach is no longer necessary for most users. 如果继续使用 TransactionScope,请注意上述限制。If you do continue to use TransactionScope then be aware of the above limitations. 建议尽可能使用前面部分中所述的方法。We recommend using the approach outlined in the previous sections instead where possible.

mysql ef6 事务_使用事务-EF6 | Microsoft Docs相关推荐

  1. rocketmq整合mysql事务_分布式事务(4)---RocketMQ实现分布式事务项目

    摘要: ,但是returnLocalTransactionState.COMMIT_MESSAG的时候*服务挂了,那么最终Brock还未收到消息的二次确定,还是个半消息,所以当重新启动的时候还是回调这 ...

  2. java mysql数据库回退_数据库事务及Java中的处理

    事 务是指一组相互依赖的操作行为,举一个举得不能再被举的例子就是银行交易,当然还有其他像网上购物,电子货币交易等等,事务的成功取决于这些相互依赖的操 作行为是否都能执行成功,只要有一个操作行为失败,就 ...

  3. rabbit和mysql事务_分布式事务原理及SpringBoot整合RabbitMQ实现可靠事件,TCC事务模型及接口幂等性...

    分布式事务 我们知道在单数据库系统中,实现数据的一致性,通过数据库的事务来处理比较简单.在微服务或分布式系统中,各个独立的服务都会有自己的数据库,而不是在同一个数据库中,所以当一组事务(如商品交易中, ...

  4. python分布式事务_分布式事务的管理--atomikos

    在一些业务场景及技术架构下,跨库的事务时不可避免的,这时候如何统一管理事务,保证事务的强一致性是整个系统稳定.可用基石.一些中间件如tuxedo.cics就是凭借这个能力占据了金融.电信.银行等很大的 ...

  5. ole db 访问接口 sqlncli 无法启动分布式事务_分布式事务,看这篇就够了

    0. 前言 1. 单数据源事务 & 多数据源事务 2. 常见分布式事务解决方案 2.1. 分布式事务模型 2.2. 二将军问题和幂等性 2.3. 两阶段提交(2PC) & 三阶段提交( ...

  6. mysql ef 分布式事务_分布式事务系列--分布式跨库查询解决方案 mysql federated引擎的使用...

    背景 在服务高度拆分,数据库不断细化切分的情况下,我们经常有连接多台数据库查询的需求,如果不断的把数据库连接的逻辑添加在代码中,那么这种耦合会越来越严重,这会给程序的拓展和维护带来很大的麻烦. mys ...

  7. mysql乐观锁与事务_[数据库事务与锁]详解七: 深入理解乐观锁与悲观锁

    注明: 本文转载自http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库 ...

  8. c# mysql ef框架_首页 C# EF6数据库第一-EF试图创建我的数据...

    好吧,我有一点背景如何到达这里.我正在重建一个旧的MVC3网站.我最近有一个Database First MVC5 EF6项目,该项目具有要使用的UI包.我复制了现有项目并撕下了几乎所有内容(所有项目 ...

  9. 服务器无法执行该事务_分布式事务、MVCC、事务隔离级别

    我们都知道,OceanBase 是一个分布式数据库,数据是打散到多台服务器上的,当一个分布式事务要执行的时候,可能需要跨越多台 OB Server,如果在执行过程中遇到各种各样的异常情况,OceanB ...

最新文章

  1. TensorFlow精选Github开源项目
  2. 23个 Git 最常用命令速查手册,值得收藏!
  3. 2018 蓝桥杯省赛 A 组模拟赛(一)数列求值+推导
  4. 敏捷开发免费管理工具——火星人预览之二:编辑故事,产品管理,组织结构...
  5. 程序员如何保护好自己的发际线
  6. windows xp sp3 原版收藏。
  7. 对倒立摆的LQR控制
  8. svnadmin的使用
  9. 分数乘法怎么用计算机计算,分数乘法计算与简单运用
  10. 什么是迁移学习?什么时候使用迁移学习?
  11. portal服务器认证系统有哪些,portal服务器认证过程问题
  12. 如何将视频中的音频提取出来
  13. web仿真或实际内存分析应用及自动化方案
  14. STI、LOD与WPE概念:STI效应对SPICE Model的影响
  15. Q-learning学习的一个小例子
  16. C#程序崩溃捕获与自动重启方法(简洁有效)
  17. c语言outl函数,Outlook MAPI开发指南
  18. twitter软件资源_从Twitter实习生到全职Twitter软件工程师的学到的知识
  19. 制作黑苹果安装U盘(Clover+OC+PE)三引导
  20. 阿里云备案+ssl申请+Nginx配置https

热门文章

  1. 目前流行的源程序版本管理软件和项目管理软件都有哪些, 各有什么优缺点?...
  2. 学习官方示例 - System.TClass
  3. 如何部署云服务器,保证应用高可用性,永不停机
  4. Java内存模型之happens-before
  5. SpringBoot @Async Example
  6. sed、grep、awk
  7. Linux shell 自启动脚本写法
  8. 样条之埃尔米特(Hermite)插值函数
  9. zabbix客户端安装二
  10. Linux CUT命令笔记