• [原创]如何写好SqlHelper


    所有写数据库应用的都会遇到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") "	" + 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

  • 相关阅读:
    八、UIViewController们之间的协作——Segue
    七、UIViewController导航栏
    六、APP开发的主角——UIViewController
    五、UI开发之核心基础——约束(深入)
    四、UI开发之核心基础——约束(实用)
    三、UI开发之核心基础——约束(入门)
    iOS开发笔记错误集
    Unity中内嵌网页插件UniWebView使用总结
    利用Aspose.Word控件实现Word文档的操作
    ReSharper 配置及用法(ZHUANG)
  • 原文地址:https://www.cnblogs.com/goldli/p/SqlHelper_Oracle.html
Copyright © 2020-2023  润新知