[原创]如何写好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") "\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


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM