在数据库工具类编写的过程中,对事务的处理操作想避免各个原子操作的事务对象赋值重复操作,想对外暴露的方法为如下形式

   public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr)

外部传入的数据库操作都使用委托统一打包,内部进行事务操作。我们首先需要明白的是,数据库事务操作在ADO.NET的编码中的体现是,DbConnection为同一个,DbCommand的Transaction为同一个。

首先我们需要识每一个数据库操作的上下文,是否在TransitionAction这个委托中,为了简单明了,在执行TransitionAction时开启一个Task,取得当前线程的ThreadID作为这个事务委托的唯一标识,并生成一个DbTransaction放入一个TransactionDic中,在SqlHelper执行类中执行SQL语句创建Connection时,取得当前的ThreadID去TransactionDic中查找,如果有对应的Transition则说明该SQL语句的执行是在一个事务中,Connection直接取Transition的数据库连接,并给DbCommand的Transition对象赋值

这个解决方案对于TransitionAction中执行方法类中的数据库操作或其他组合操作也是可行的,但是对于嵌套事务还需要进一步改进。

比如我封装好一个框架的工作流方法MethodA,自带事物执行,但是需要与业务更新方法MethodB进行事物组合操作,上述方案并不能满足要求,需要我们进行改进,判断当前的事物TransitionAction是否是嵌套事务,即TransitionActionB实际是打包在TransitionActionA中的。在TransitionAction的DbTransaction添加的过程中,我们需要取到Task之外的ThreadID,这里称作为RootThreadID,同时维护一个ConcurrentDictionary<string, List<string>> TransitionIDMapDic,用于维护RootThreadID与嵌套事务的ThreadID的关系,在创建Task时就可以判断当前的ThreadID是否在TransactionDic,存在就是嵌套事务,需要将当前的TransitionAction合并到Root事物中

TransactionManage 代码

 public class TransactionManage
{
private static ConcurrentDictionary<string, LocalTransaction> TransactionDic = new ConcurrentDictionary<string, LocalTransaction>();
private static ConcurrentDictionary<string, List<string>> TransitionIDMapDic = new ConcurrentDictionary<string, List<string>>();
public static void AddTransition(string TransitionID,string RootThreadID, DbTransaction Transition,Action TransitionAction)
{
LocalTransaction LT = new LocalTransaction();
LT.RootThreadID = RootThreadID;
LT.TransitionID = TransitionID;
LT.Transition = Transition;
//执行列表增加Action
LT.AddTransitionAction(TransitionAction);
TransactionDic.TryAdd(TransitionID, LT);
//增加事务根线程ID与嵌套事务相关事务ID
TransitionIDMapDic.TryAdd(RootThreadID, new List<string>() { TransitionID }); } public static void ContactTransition(string TransitionID, string RootThreadID,Action TransitionAction)
{
LocalTransaction LT = TransactionDic[RootThreadID];
if (!TransactionDic.ContainsKey(LT.RootThreadID))
{
LT.TransitionID = TransitionID;
//执行列表增加Action
LT.AddTransitionAction(TransitionAction);
TransactionDic.TryAdd(TransitionID, LT);
//增加事务根线程ID与嵌套事务相关事务ID
List<string> TransitionIDS = TransitionIDMapDic[LT.RootThreadID];
TransitionIDS.Add(TransitionID);
TransitionIDMapDic[LT.RootThreadID] = TransitionIDS;
}
else
{
ContactTransition(TransitionID, LT.RootThreadID, TransitionAction);
}
} public static string GetRootID(string TransitionID)
{
LocalTransaction LT = TransactionDic[TransitionID];
if (!TransactionDic.ContainsKey(LT.RootThreadID))
{
return LT.RootThreadID;
}
else
{
return GetRootID(LT.RootThreadID);
}
} public static LocalTransaction GetTransition(string TransitionID)
{
LocalTransaction LT = null;
TransactionDic.TryGetValue(TransitionID, out LT);
return LT;
}
public static bool ContainsTransition(string TransitionID)
{
return TransactionDic.ContainsKey(TransitionID);
}
public static void RemoveTransition(string TransitionID)
{
string RootID = GetRootID(TransitionID);
List<string> TransitionIDList = null;
TransitionIDMapDic.TryRemove(RootID, out TransitionIDList);
foreach (string TransitionIDItem in TransitionIDList)
{
LocalTransaction LT = null;
TransactionDic.TryRemove(TransitionIDItem, out LT);
}
}

对外事物执行方法

   public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr)
{
bool IsSuccess = true;
ExceptionStr = string.Empty;
string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
var TrabsitionTask = new Task<LocalTransactionResult>(() =>
{
string TransitionID = Thread.CurrentThread.ManagedThreadId.ToString();
LocalTransactionResult Result = new LocalTransactionResult();
if (!TransactionManage.ContainsTransition(RootThreadID))
{
using (DbConnection connection = DBExecute.CreateConnection(ConnectionString))
{
connection.Open();
DbTransaction Transaction = connection.BeginTransaction();
TransactionManage.AddTransition(TransitionID, RootThreadID, Transaction, TransitionAction);
try
{
TransactionManage.GetTransition(TransitionID).Execute();
Transaction.Commit();
}
catch (System.Exception e)
{
Result.ExecuteStatus = false;
Result.ExceptionMessage = e.Message;
Transaction.Rollback();
}
finally
{
Transaction.Dispose();
connection.Close();
connection.Dispose();
Transaction = null;
TransactionManage.RemoveTransition(TransitionID);
}
return Result;
}
}
else
{
//当前是嵌套事务,不执行,由根事务统一执行
TransactionManage.ContactTransition(TransitionID, RootThreadID, TransitionAction);
Result.ExecuteStatus = true;
Result.ExceptionMessage = string.Empty;
return Result;
} });
TrabsitionTask.Start();
TrabsitionTask.Wait();
IsSuccess = TrabsitionTask.Result.ExecuteStatus;
ExceptionStr = TrabsitionTask.Result.ExceptionMessage;
return IsSuccess; }

完整模块代码地址:https://gitee.com/grassprogramming/FastExecutorCore/tree/master/code/FastCore/FastCore/FastORM

注:个人感觉使用线程的方式虽然很方便但是实际使用过程中多线程可能会出现问题,后续会对执行类进行上下文对象的绑定改造

ADO.NET事务封装的更多相关文章

  1. OracleHelper(对增删改查分页查询操作进行了面向对象的封装,对批量增删改操作的事务封装)

    公司的一个新项目使用ASP.NET MVC开发,经理让我写个OracleHelper,我从网上找了一个比较全的OracleHelper类,缺点是查询的时候返回DataSet,数据增删改要写很多代码(当 ...

  2. 把事务封装成类似Serializable用法的特性

    把事务封装成类似Serializable用法的特性 最近几天上班没事可做就想着整理常用的类库方法,验证.消息.分页.模版引擎.数据库操作.ini操作.文本操作.xml操作等,最后就是现在这个事务特性. ...

  3. ADO.NET事务

    在发布System.Transaction命名空间之前,可以直接用ADO.NET创建事务,也可以通过组件.特性和COM+运行库(位于System.EnterpriseServices命名空间中)进行事 ...

  4. Dapper的封装、二次封装、官方扩展包封装,以及ADO.NET原生封装

    前几天偶然看到了dapper,由于以前没有用过,只用过ef core,稍微看了一下,然后写了一些简单的可复用的封装. Dapper的用法比较接近ADO.NET所以性能也是比较快.所以我们先来看看使用A ...

  5. SQL Server 2008 R2——VC++ ADO 操作 事务

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  6. ADO.NET 事务控制

    在ADO.NET 中,可以使用Connection 和Transaction 对象来控制事务.若要执行事务,请执行下列操作: 1.调用Connection 对象的BeginTransaction 方法 ...

  7. EF事务封装

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

  8. ADO执行事务

    在工作中遇到,需要批量提交的.在sql2008以后有表变量定义,可以实现.但个人比较习惯用C#,就有下面代码,直接上代码... using (SqlConnection conn = new SqlC ...

  9. ADO 事务

    Ado.Net事务处理.在ADO.NET 中,可以使用Connection 和Transaction 对象来控制事务.若要执行事务,请执行下列操作:• 调用Connection 对象的BeginTra ...

随机推荐

  1. Java博客专栏

    1. Java23种设计模式 2. JVM虚拟机 3. 设计模式6大原则 4. Java代码性能优化总结 5. 三种代理 6. iText操作PDF 7. 解析XML的4种方式 8. 面向对象思想 9 ...

  2. CUDA学习(四)之使用全局内存进行归约求和(一个包含N个线程的线程块)

    问题:使用CUDA进行数组元素归约求和,归约求和的思想是每次循环取半. 详细过程如下: 假设有一个包含8个元素的数组,索引下标从0到7,现通过3次循环相加得到这8个元素的和,使用一个间隔变量,该间隔变 ...

  3. P4语言环境安装(一)前端编译器p4c、后端编译器p4c-bm2-ss

    这个P4安装环境是在2020-2-8安装的,安装环境卡了我好几天,把遇到的问题记录下来,有需要的同学可以参考一下,要是说错了或者有问题的话,评论或mail:guidoahead@163.com联系我都 ...

  4. es学习(三):分词器介绍以及中文分词器ik的安装与使用

    什么是分词 把文本转换为一个个的单词,分词称之为analysis.es默认只对英文语句做分词,中文不支持,每个中文字都会被拆分为独立的个体. 示例 POST http://192.168.247.8: ...

  5. C语言I作业1

    1 你对软件工程专业或计算机科学与技术专业了解是怎样的? 软件工程顾名思义就是工程化的方法生产软件的一门学科.涉及到程序设计语言,数据库,软件开发工具,系统平台,标准,设计模式等方面. 2 你了解c语 ...

  6. FFMPEG学习----使用SDL构建视频播放器

    #include <stdio.h> #include <string.h> extern "C" { #include "libavcodec/ ...

  7. Http POST 提交 415错误 Unsupported Media Type 解决方案

    1 问题 在调用webapi post 提交时出现 415 Unsupported Media Type 错误 前端代码如下: $.post("/api/student/poststuden ...

  8. CSS绝对定位absolute详解

    转:https://www.jianshu.com/p/a3da5e27d22b     之前介绍过CSS浮动float详解,本篇介绍的绝对定位absolute和浮动float有部分相似性.如果能理解 ...

  9. shell命令之一天一见:awk

    AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一. 这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯.彼得·溫伯格和布萊恩·柯林漢姓氏的首个字 ...

  10. for和while——python中的循环控制语句详解

    循环语句在绝大多数的语言中,都是必不可少的一种控制语句,循环语句允许我们执行一个语句或语句组多次.在python中有for循环和while循环两种,讲到这里,就不得不提到我们的迭代器对象 迭代器 迭代 ...