所有写数据库应用的都会遇到SqlHelper。每个人实现的也不同,网上现成的例子也很多。但在实际操作中,大部分都不实用。什么样的才是实用的?答:适合应用场景的!

下面来介绍下我写的一个关于Oracle的SqlHelper。没有进行大规模及性能测试。

首先来说下为什么写这个SqlHelper。在以往的桌面程序开发中,我遇到最多的Sql操作,一般不会涉及多个表同时操作,即使有,在使用SqlHelper时用一个Transaction就可以了。

但现在场景换了。在Web里我们将业务操作与具体数据库操作分离了成 Ba 与Da(人为强制性的)。在Ba里对业务操作进行必要的检测,然后调用Da读写数据。Ba可以供其它Ba操作时复用。

在复用时,我们要确保多个以及多级Ba在同一个事务(如果需要)里,同时Ba只能访问自己的Da。这样的操作环境催生了现在我要展示的SqlHelper。然而,当我写完了这个SqlHelper后,发现它可以很好的完成桌面以及Web应用中对Sql的操作。下面是桌面应用的测试用例

    public class Ta : Blo
    {
        public int InsertAndNext()
        {
            var sql = "INSERT INTO TB_SYS_DD(DDID,DICNAME) values('{0}','{1}')  returning DDID into :result";//注意结尾不需要使用 ;
            Trans.SqlHelper.CommandText = string.Format(sql, "2001", "测试项");
            var para = new OracleParameter("result", OracleType.Number);
            para.Direction = ParameterDirection.Output;
            Trans.SqlHelper.AddParameter(para);
            Trans.SqlHelper.Execute();
            return Convert.ToInt32(para.Value);
        }         public void Add()
        {
            var sql = "INSERT INTO TB_SYS_DD values('{0}','{1}')";
            Trans.SqlHelper.CommandText = string.Format(sql, "2001", "测试项");
            Trans.SqlHelper.Execute();
        }
    }     public class Tb : Blo
    {
        public void Add()
        {
            var sql = "INSERT INTO TB_SYS_DDDETAIL values('{0}','{1}','{2}')";
            Trans.SqlHelper.CommandText = string.Format(sql, "2000", "1", "测试项一");
            Trans.SqlHelper.Execute();
        }         public string GetMaxDicName()
        {
            var sql = "select d.dicname from TB_SYS_DD d where d.ddid = (select max(ddid) from TB_SYS_DD)";
            Trans.SqlHelper.CommandText = sql;
            var x = Trans.SqlHelper.ExecuteScalar();
            return x.ToString();
        }
    }     public class Tc : Blo
    {
        public void Add()
        {
            var sql = "INSERT INTO TB_SYS_RESETPWD(userId,guid,Time) values('{0}','{0}',)";
            Trans.SqlHelper.CommandText = string.Format(sql, "2000", "1");
            Trans.SqlHelper.Execute();            
        }         public void Update()
        {
            var sql = "update TB_SYS_DD set dicname = '{0}' where ddid = 2000";
            Trans.SqlHelper.CommandText = string.Format(sql, "值");
            Trans.SqlHelper.Execute();
        }     }

测试代码

        //直接使用sqlhelper的情况
        private void button1_Click(object sender, EventArgs e)
        {
            using (var helper = new OracleHelper { ConnectionString = txtOracle.Text, CommandText = txtSql.Text })
            {
                Trace.WriteLine(helper.DataSource);
                var dt = helper.GetDataTable();
                if (dt != null && dt.Rows.Count > 0)
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        lbResult.Items.Add(row.Field<string>("TABLE_NAME") + "\t" + row.Field<string>("COMMENTS"));
                    }
                }
            }
        }         //使用业务逻辑创建一个事务。将所有的操作包含在同一事务里
        private void button2_Click(object sender, EventArgs e)
        {
            var a = new Ta();
            //a.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            a.Trans.Begin();             //下面的两过程效果相同。但建议使用第二种。更容易理解
            var b = new Tb {Trans = a.Trans};
            //var b = new Tb();
            //a.Trans.AddBusiness(b);             var c = new Tc();
            a.Trans.AddBusiness(c);             try
            {
                a.Add();
                b.Add();
                c.Add();
                a.Trans.Commit();
            }
            catch (Exception ex)
            {
                a.Trans.Rollback();
                
                throw new Exception();
            }
        }         //插入之后返回值,如自增Id
        private void button3_Click(object sender, EventArgs e)
        {
            var a = new Ta();
            a.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            a.Trans.Begin();             try
            {
                var i = a.InsertAndNext();
                MessageBox.Show(i.ToString());
                a.Trans.Commit();
            }
            catch (Exception ex)
            {
                a.Trans.Rollback();
                throw;
            }
        }         /*
            在一个事务里,对N个表进行操作(1)。
           这时有其它的连接对相同的表操作。操作是按正常情况执行(2)。
           若(2)使用(1)表中的结果,那么如果(1)的事务未提交,则(2)无法访问(1)中最新的值         
         */
        private void button4_Click(object sender, EventArgs e)
        {
            var a = new Ta();
            a.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            a.Trans.Begin();             var b = new Tb();
            a.Trans.AddBusiness(b);             var c = new Tc();
            a.Trans.AddBusiness(c);             try
            {
                a.Add();
                Thread.Sleep(1000 * 60 * 5);//等5分钟
                b.Add();
                c.Add();
                a.Trans.Commit();
            }
            catch (Exception ex)
            {
                a.Trans.Rollback();
                throw;
            }
        }         private void button5_Click(object sender, EventArgs e)
        {
            var b = new Tb();
            b.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            try
            {
                var x = b.GetMaxDicName();
                MessageBox.Show(x);
            }
            catch (Exception ex)
            {
                throw;
            }
        }         private void button6_Click(object sender, EventArgs e)
        {
            var c = new Tc();
            c.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            try
            {
                c.Update();
            }
            catch (Exception ex)
            {
                throw;
            }
        }
    //外层事务,内层独立事务    
        private void button7_Click(object sender, EventArgs e)
        {
            var a = new Ta();
            a.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            a.Trans.Begin();             var b = new Tb();
            b.Trans.SqlHelper.ConnectionString = txtOracle.Text;
            var c = new Tc();
            c.Trans.SqlHelper.ConnectionString = txtOracle.Text;             try
            {
                a.Add();
                try
                {
                    b.Trans.Begin();
                    b.Add();
                    b.Trans.Commit();
                }
                catch (Exception)
                {
                    b.Trans.Rollback();
                    throw;
                }
                try
                {
                    c.Trans.Begin();
                    c.Add();
                    c.Trans.Commit();
                }
                catch (Exception)
                {
                    c.Trans.Rollback();
                    throw;
                }
                a.Trans.Commit();
            }
            catch (Exception ex)
            {
                a.Trans.Rollback();
                throw;
            }
        }     }

看完以上代码。你现在最关心的是如何实现事务共享的,以及如何区分事务的所有者及是否可以进行提交。

秘密其实很简单,能过三个地方来控件。

1、是否共享

public class Blo 为业务对象基类,我给它一个事务控制的属性对象 public Trans Trans { get; set; }

2、Trans 对象为事务控制器。给它设定一个属性 public bool IsInherited { get; set; }  用于标识它的事务是否从其它事务得来的。
3、Blo 的 Trans 的属性读写器

        public Trans Trans
        {
            get
            {
                if (_trans != null) return _trans;
                _trans = new Trans(this) {IsInherited = false};
                return _trans;
            }
            set
            {
                if (_trans == null)
                {
                    _trans = new Trans(this);
                }
                _trans.SqlHelper = value.SqlHelper;
                _trans.IsInherited = true;
            }
        }

通过这三个地方我们就完全可以控件事务的统一访问了。

说了这么多还是把dll文件上传上来。如果哪个兄弟有心可以对此dll进行性能测试。当然需要.net 4

[原创]如何写好SqlHelper的更多相关文章

  1. [原创]如何写好SqlHelper 之终章

    精简的美丽...... 标题有点大.但是,我觉得99%的接近了. 好了,下面我们来说说一个SqlHelper为了适应各种不同的业务需要,它应该具备哪些基本要素. 第一点.可控的事务. 事务是数据库操作 ...

  2. 自己写的SqlHelper

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  3. 青鸟 王云鹏老师写的SqlHelper 泛型方法,反射,支持实体类

    1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: ...

  4. 根据传智写的SqlHelper

    using System; using System.Configuration; using System.Data; using System.Data.SqlClient; namespace ...

  5. 自己写的SqlHelper,提示在调用"Fill"前,SelectCommand 属性尚未初始化.错误

    namespace 操作数据{    class SqlHelper    {        public DataSet SqlTODs(string cmdstring)        {     ...

  6. [原创]python写的sniffer

    import socket s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,8) while 1: data=s.recv(65535) print ...

  7. redmine中创建项目与跟踪标签(原创)

    今天来说下本公司所用到的项目管理工具redmine,总体来说还是比较好用的.redmine中可以记录项目的整个过程,可创建跟踪标签(里程碑.需求用例.功能.任务.缺陷)来进行对项目的管控.跟踪标签根据 ...

  8. ADO.NET复习——自己编写SqlHelper类

    今天复习了一次ADO.NET基础,整理一下自己的认为的重点: 编写SqlHelper类,方便我们执行数据库语句,这时可以直接调用封装在SqlHelper类的方法.现在大多数公司面试的时候,给你的面试题 ...

  9. 再学习sqlhelper

    在机房收费重构系统的时候,第一次学习sqlhelper.当时感觉比较简单,没有写博客总结,现在又经过了图书馆的学习,感觉还是有必要写一写的. SqlHelper是一个基于.NETFramework的数 ...

随机推荐

  1. LeetCode Pascal's Triangle II (杨辉三角)

    题意:给出杨辉三角的层数k,返回最后一层.k=0时就是只有一个数字1. 思路:滚动数组计算前一半出来,返回时再复制另一半.简单但是每一句都挺长的. 0ms的版本: class Solution { p ...

  2. SqlServer中decimal(numeric )、float 和 real 数据类型的区别[转]

    decimal(numeric )             同义,用于精确存储数值 float 和 real                      不能精确存储数值   decimal 数据类型最 ...

  3. win7(64位)+IE8+QC9.0

    环境win7(64位)+IE8+QC9.0出现的问题IE8访问QC9.0有时访问登录显示正常,但是有时访问QC页面无法显示正常,然后在ie8中安全中设置“启用内存保护帮助减少联机攻击*”也无法找到该项 ...

  4. 设计原则 Design Principle

    Design Principle设计原则 最近由于碰到要参与设计一个音频处理系统,有人提议用一个大的全局变量结构体来做状态信息交流的地方,引起了我对设计一个系统的思考,于是找到了如下资料,当然,关于这 ...

  5. 50道经典的JAVA编程题 (11-15)

    50道经典的JAVA编程题 (11-15),新年的第一天,继续啦...\(^o^)/~,这50道题都跨年了啊...哈哈 [程序11] TestTN.java 题目:有1.2.3.4个数字,能组成多少个 ...

  6. gimp之旅

    随着大学生活的告一段落,新的征途已经开始了.鉴于本人如此喜欢旅游,如此喜欢拍照,如此喜欢处理图片,所以打算在照片处理上下点功夫.总所周知,图像处理软件大牛级的就属windows下的photoshop以 ...

  7. 自编译安装nginx

    1. 下载nginx,并解压 http://nginx.org/ 2. 下载health check模块 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 1 ...

  8. Petshop学习第三天

    ASP.NET缓存 ASP.NET充分利用缓存机制,通过某种方法,将系统需要的数据对象.Web页面存储在内存中,使得Web站点需要这些数据时,不经过繁琐的数据库连接.查询和复杂的逻辑运算,就可以触手可 ...

  9. 怎样让你的代码更好的被JVM JIT Inlining

    好书推荐:Effective Java中文版(第2版) JVM JIT编译器优化技术有近100中,其中最最重要的方式就是内联(inlining).方法内联可以省掉方法栈帧的创建,方法内联还使让JIT编 ...

  10. TCP/IP协议栈及OSI参考模型详解

    OSI参考模型 OSI RM:开放系统互连参考模型(open systeminterconnection reference model) OSI参考模型具有以下优点: 简化了相关的网络操作: 提供设 ...