[原創]如何寫好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