.NET事务
一、概述
1、事务ACID特性
事务将一系列的工作视为一个工作单元,它具有 ACID 特性:
- A:Atomicity 不可分性
也就是说事务中有多项工作,如果有一项工作失败了,整个事务就算失败了。 - C:Consistency 一致性
事务完成时,全部数据必须维持一致性的状态。对于关系数据库,简单地来说就是没有破坏数据完整性。 - I:Isolation 隔离性
事务与其他事务是隔离的,也就是说一个事务的一项工作对数据进行修改时,如果整个事务还没有结束,其他事务就无法知道这个数据发生了修改。 - D:Durability 持久性
事务完成后,其作用便永远存在于系统之中。
2、.NET开发者用到的5种事务机制:
- SQL和存储过程级别的事务。(数据库事务)
- ADO.NET级别的事务。
- ASP.NET页面级别的事务。
- 企业级服务COM+事务。
- System.Transactions 事务处理。
这5种事务机制有着各自的优势和劣势,分别表现在性能、代码数量和部署设置等方面。开发人员可以根据项目的实际情况选择相应的事务机制。
二、数据库事务
1、不同数据库的事务规则
数据库事务是其他事务模型的基础,当一个事务创建时不同数据库系统都有自己的规则。
- SQL Server默认在自动提交的模式下工作,每个语句执行完后都会立即提交;
- Oracle则需要你包含一个提交语句。
- 当一个语句通过OLE DB执行时,它执行完后一个提交动作会被附加上去。
例如:SQL Server数据库T-SQL语句中显示指定事务
declare @TranName varchar(20);
select @TranName = 'MyTransaction'; begin transaction @TranName;
go use AdventureWorks;
go delete from AdventureWorks.HumanResources.JobCandidate where JobCandidateID = 13;
go commit transaction MyTransaction;
go
或在存储过程中使用
create procedure Tran1
as
begin tran;
set xact_abort on; --set xact_abort on表示遇到错误立即回滚。
insert into P_Category ( CategoryId, Name ) values ( '1', 'test1' );
insert into P_Category ( CategoryId, Name ) values ( '2', 'test2' );
commit tran;
go
2、数据库事务的优势和限制
(1)优势:
- 所有的事务逻辑包含在一个单独的调用中。
- 拥有运行一个事务的最佳性能。
- 独立于应用程序。
(2)限制:
- 事务上下文仅存在于数据库调用中。
- 数据库代码与数据库系统有关。
三、ADO.Net事务
ADO.Net事务为System.Data.Common.DbTransaction类的各种派生类。ADO.Net事务不是分布式事务,不支持跨多个连接,它总是关联到一个连接上的本地事务上。
ADO.NET 显式事务占用资源少、速度快,但功能简单,只能管理单一对象和单一持久资源间的事务。
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{
conn.Open();
using (SqlTransaction tran = conn.BeginTransaction())
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn; cmd.Transaction = tran;
cmd.CommandType = CommandType.Text;
try
{
cmd.CommandText = "insert into TranTable(Priority) values(1)";
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into TranTable(Priority) values(256)";
cmd.ExecuteNonQuery();
tran.Commit();
Response.Write("Ok");
}
catch (SqlException ex)
{
tran.Rollback();
Response.Write("Error:" + ex.Message);
}
}
}
conn.Close();
}
四、System.EnterpriseServices自动事务处理
不需要显示进行事务处理,运行库自动创建事务。多个对象能轻松的运行在同一个事务中。但它需要COM+主机模型。
使用此技术的类必须派生自ServicedComponen类。
[Transaction(TransactionOption.Required)]
public class OrderContrl : ServicedComponent
{
[AutoComplete]
public void NewOrder(Order order)
{
using (OrderData data = new OrderData())
{
data.Insert(order);
}
}
}
五、System.Transactions事务
System.Transactions是所有事务处理类的基类。
System.Transactions基础结构通过支持SQL Server、ADO.NET、MSMQ和Microsoft分布式事务协调器(MSDTC)中启动的事务,使得整个平台的事务编程变得简单和高效。
它既提供了基于Transaction 类的显式编程模型,也提供了使用TransactionScope类的隐式编程模型,它里面的事务由基础设施自动管理。强烈建议使用更简单的隐式开发模型TransactionScope。
1、显式事务(Explicit Transaction)
提交、回滚事务都由程序员编程来决定的方式,叫“显式事务(Explicit Transaction)”。Transaction 类及其派生类为显式事务。
2、Transaction类的派生类
- CommittableTransaction:可提交的事务
- DependentTransaction:依赖事务
- SubordinateTransaction:可以委托的下属事务
3、Transaction类成员
- Current: 获取或设置环境事务。
- IsolationLevel: 获取事务的隔离级别。
- TransactionInformation: 检索有关某个事务的附加信息。
- DependentClone(DependentCloneOption) : 创建事务的依赖复本。
- Rollback() : 回滚(中止)事务。
- Dispose(): 释放由该对象占用的资源。
- TransactionCompleted: 指示事务已完成。
六、可提交的事务:CommitableTransaction(显式事务)
唯一支持提交的事务类是CommitableTransaction,它直接继承自Transaction。
CommittableTransaction提供了“Commit”同步方法和“BeginCommit”、“EndCommit”异步方法组合对事务的提交。
创建CommittableTransaction事务并不会自动设置环境事务。
CommittableTransaction事务不能被重用。可以将数据库连接登记到事务。
注意:只有一个DbConnection时为本地事务;当存在多个DbConnection时才会启动MSDTC(MSDTC不够稳定,尽量避免引入分布式服务)
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{
using (CommittableTransaction ct = new CommittableTransaction ())
{
conn.Open();
conn.EnlistTransaction(ct);//将数据库连接登记到事务
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
try
{
cmd.CommandText = "insert into TranTable(Priority) values(1)";
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into TranTable(Priority) values(256)";
cmd.ExecuteNonQuery();
ct.Commit(); //提交事务
Response.Write("Ok");
}
catch (SqlException ex)
{
ct.Rollback();//回滚事务
Response.Write("Error:" + ex.Message);
}
}
conn.Close();
}
}
七、环境事务:TrasactionScope(隐式事务,推荐)
TransactionScope为隐式事务。它为一组事务型操作创建一个执行范围,而这个范围始于TransactionScope创建之时,结束于TransactionScope被回收(调用Dispose方法)。
TransactionScope实现了IDisposable接口,除了Dispose方法之外,仅仅具有一个唯一的方法:Complete()。
目前 TransactionScope 只能处理数据库的事务,对于其他事务,如 I/O,目前的 .NET 版本无法处理。
using (SqlConnection conn = new SqlConnection("Data Source=.; Initial Catalog=TestDb; Integrated Security=SSPI;"))
{
using (TransactionScope ts = new TransactionScope())
{
conn.Open();
try
{
SqlCommand cmd = new SqlCommand(conn);
cmd.CommandText = "INSERT INTO [Test]([Name],[Value]) VALUES ('测试1','1')";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO [Test]([Name],[Value]) VALUES ('测试2','2')";
cmd.ExecuteNonQuery(); ts.Complete();
}
catch (SqlException)
{
}
conn.Close();
}
}
TransactionScope却有一组丰富的构造函数。我们先来看看这些构造函数相应的参数如何影响TransactionScope对事务控制的行为。
void Main()
{
TransactionOptions transactionOptions = new TransactionOptions()
{
IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
Timeout = new TimeSpan(0, 2, 0)//超时间隔两分钟
}; using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
Transaction.Current.TransactionCompleted += (sender, args) =>
{
Console.Write(args.Transaction.TransactionInformation.LocalIdentifier);
} AddStudent(new Student { });
scope.Complete();//提交事务
}
} public void AddStudent(Student s)
{
SqlConnection conn = new SqlConnection();//环境事务内新建的连接自动附加到事务
//如果连接在TransactionScope建立之前已存在,需要手工用conn.EnlistTrasaction(Transaction.Current)登记事务
conn.Open();
try
{
SqlCommand command = new SqlCommand();
}
catch (Exception ex)
{
throw;
}
}
1、隔离级别IsolationLevel
7个隔离级别之中,Serializable具有最高隔离级别,代表的是一种完全基于序列化(同步)的数据存取方式。按照隔离级别至高向低,7个不同的隔离级别代表的含义如下:
- Serializable:可序列化。(默认,最高级别)可以在事务期间读取可变数据,但是不可以修改,也不可以添加任何新数据;
- RepeatableRead:可重复读。可以在事务期间读取可变数据,但是不可以修改。可以在事务期间添加新数据;
- ReadCommitted:可读已提交的数据。不可以在事务期间读取可变数据,但是可以修改它;
- ReadUncommitted:读未提交的数据。可以在事务期间读取和修改可变数据;
- Snapshot:快照。可以读取可变数据。在事务修改数据之前,它验证在它最初读取数据之后另一个事务是否更改过这些数据。如果数据已被更新,则会引发错误。这样使事务可获取先前提交的数据值;
- Chaos:混乱。无法覆盖隔离级别更高的事务中的挂起的更改;
- Unspecified:未指定。正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。如果设置了此值,则会引发异常。
2、嵌套环境事务
using (TransactionScope outerScope = new TransactionScope())
{
using (TransactionScope innerScope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
//事务型操作
innerScope.Complete();
}
//事务型操作
outerScope.Complete();
}
3、TransactionScopeOption
使用TransactionScopeOptions可以改变TransactionScope的默认事务类型。
- Required: (默认)如果已经存在一个事务,那么这个事务范围将加入已有的事务。否则,它将创建自己的事务。
- RequiresNew: 这个事务范围将创建自己的事务。
- Suppress:抑制。 将事务范围内的环境事务设为空,意味着事务范围内的操作并不受事务的控制。当部分代码需要留在事务外部时,可以使用该选项。
4、MSDTC组件设置:
一般情况下只要你使用"TransactionScope",都要配置MSDTC,要配防火墙,要开139端口,这个端口不可以更改。
- 如果WEB服务器和数据库是在同一台服务器上,TransactionScope使用的是本地事务,这时不需要配置MSDTC。
- 如果WEB服务器和数据库不在同一台服务器上,TransactionScope会自动提升事务级别为分布式事务,这时就需要配置MSDTC。
对MSDTC组件设置:控制面板--->管理工具--->服务 中,开启Distributed Transaction Coordinator 服务。
- 控制面板->管理工具->组件服务->计算机->我的电脑->右键->属性,选择MSDTC页, 确认"使用本地协调器"。
- 点击下方"安全配置"按钮
- 勾选: "允许网络DTC访问","允许远程客户端","允许入站","允许出站","不要求进行身份验证".
- 对于数据库服务器端, 可选择"要求对呼叫方验证"
- 勾选:"启用事务Internet协议(TIP)事务"。
- 在双方防火墙中增加MSDTC.exe例外
可用命令行: netsh firewall set allowedprogram %windir%/system32/msdtc.exe MSDTC enable
八、依赖事务DependentTransaction,跨多个线程调用事务(显式事务)
一个环境事务绑定到一个线程上,如果新建了一个线程它就不会有第一个线程中的环境事务,两个线程中的事务完全独立。
如果多个线程使用同一个环境事务,需要给新线程传递一个依赖事务,调用Transaction的DependentClone方法创建依赖事务。
依赖事务通过DependentTransaction类型表示,和CommittableTransaction一样,DependentTransaction也是Transaction的子类。
DependentTransaction依赖于现有的Transaction对象而存在,相当于被依赖事务的子事务,具有一个唯一的方法成员:Complete。调用这个方法意味着向被依赖事务发送通知,表明所有与依赖事务相关的操作已经完成。
DependentClone方法具有一个DependentCloneOption枚举类型的参数:
- BlockCommitUntilComplete:表示被依赖事务在提交前会一直等待接收到依赖事务(子事务)的通知(调用Complete或者Rollback方法)或者超过事务设定的超时时限;
- RollbackIfNotComplete:如果被依赖事务在依赖事务(子事务)之前先完成,直接将被依赖的事务回滚,并抛出TransactionAbortedException异常。
下面的代码示例演示如何创建一个依赖事务来管理两个并发任务,具体为克隆一个依赖的事务并将其传递给辅助线程。
void Main()
{
using (TransactionScope scope = new TransactionScope())
{
DependentTransaction dTx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
Thread thread = new Thread(ThreadMethod);
thread.Start(dTx);
/* Do some transactional work here, then: */
scope.Complete();
}
} public void ThreadMethod(object transaction)
{
DependentTransaction dTx = transaction as DependentTransaction;
try
{
//将DependentTransaction对象作为TransactionScope的参数,以初始化环境事务
using (TransactionScope ts = new TransactionScope(dTx))
{
/* Perform transactional work here */
ts.Complete();//完成环境事务
}
}
finally
{
dTx.Complete();//完成依赖事务
dTx.Dispose();
}
}
.NET事务的更多相关文章
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- SQLServer事务同步下如何收缩日志
事务同步是SQLServer做读写分离的一种常用的方式. 随着业务数据的不断增长,数据库积攒了大量的日志,为了腾出硬盘空间,需要对数据库日志进行清理 订阅数据库的日志清理 因为订阅数据库所有的数据都来 ...
- 事务日志已满,原因为“ACTIVE_TRANSACTION”
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 异常处理汇总-数据库系列 http://www.cnblogs.com/dunitia ...
- Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
- Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
- CRL快速开发框架系列教程七(使用事务)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- 玩转spring boot——结合JPA事务
接着上篇 一.准备工作 修改pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- PHP中PDO事务的使用方法
事务 (Transaction) 是操作数据库中很重要的一个功能, 它可以让你预定一条, 或者一系列 SQL 语句, 然后一起执行. 在执行的过程中, 如果其中的某条执行失败, 可以回滚所有已更改的操 ...
- Hibernate中事务的隔离级别设置
Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下
随机推荐
- 读写锁--ReentrantReadWriteLock
读写锁,对于读操作来说是共享锁,对于写操作来说是排他锁,两种操作都可重入的一种锁.底层也是用AQS来实现的,我们来看一下它的结构跟代码: ------------------------------- ...
- spring mvc中DispatcherServlet如何得到ModelAndView的
首先看下面这种张图,这张图说明了spring mvc整体的流程. 本文讲的就是如何从DispatcherServlet中得到ModerAndView的过程. 首先看DispatherServlet这个 ...
- C语言入门语法
一.数据类型 常量 1.通过预处理声明常量 #include <stdio.h> #define PRICE 100 int main() { printf("价格:%d\n&q ...
- js实现页面跳转的八种方式
整理一下JavaScript八种跳转方式,欢迎评论补充! 第一种方法: <script> window.location.replace('http://www.cnblogs.com/c ...
- openlayers 各种图层,持续更新
/*高德地图*/ var vectorLayerLine = new ol.layer.Tile({ source: new ol.source.XYZ({ urls: [ "http:// ...
- TransitionEnd事件
定义和用法: transitionend 事件在 CSS 完成过渡后触发. 注意: 如果过渡在完成前移除,例如 CSS transition-property 属性被移除,过渡事件将不被触发. 浏览器 ...
- eclipse svn使用
简单介绍一些基本操作 1.同步在Eclipse下,右击你要同步的工程->team->与资源库同步->这时会进入同步透视图,会显示出本机与SVN上内容有不同的文件,双击文件名,会显示出 ...
- Bootstrap + AngularJS+ Ashx + SQL Server/MySQL
去年年底12月,为适应移动端浏览需求,花了1个月时间学习Bootstrap,并将公司ASP网站重构成ASP.NET. 当时采取的网站架构: Bootstrap + jQuery + Ashx + SQ ...
- 最长公共子序列(LCS)思维导图
- Python爬虫教程-18-页面解析和数据提取
本篇针对的数据是已经存在在页面上的数据,不包括动态生成的数据,今天是对HTML中提取对我们有用的数据,去除无用的数据 Python爬虫教程-18-页面解析和数据提取 结构化数据:先有的结构,再谈数据 ...