DataReader鏈接關閉解惑篇
看到有帖子:DataReader的關閉問題疑惑篇 ,大伙對鏈接關閉問題看似比較迷惑,這里就給解說一下:
不管是啥xxDataReader,都是繼承DataReader實現(xiàn)的,所以是有共性的,因此標題就以DataReader為題了。
情況一:DataReader 默認鏈接不關閉
示例代碼:
- static void Main(string[] args)
- {
- SqlConnection con = new SqlConnection("server=.;database=MySpace;uid=sa;pwd=123456");
- con.Open();
- SqlCommand com = new SqlCommand("select top 1 id from blog_user",con);
- SqlDataReader sdr = com.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
- while (sdr.Read())
- {
- }
- Console.WriteLine(sdr.IsClosed);
- Console.WriteLine(con.State.ToString());
- Console.ReadLine();
- }
結(jié)論是:
False
Open
說明:默認無論是不是加System.Data.CommandBehavior.CloseConnection,讀取時數(shù)據(jù)庫鏈接不會幫你關閉。
情況二:DataReader 鏈接已關閉
示例代碼:[以下是原文的代碼]
- protected void bind()
- {
- SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["constr"].ToString());
- conn.Open();
- SqlCommand cmd = new SqlCommand("GetAllUser", conn);
- SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
- repeater1.DataSource = sdr;
- repeater1.DataBind();
- Response.Write(sdr.IsClosed.ToString() + "<br/>");
- Response.Write(conn.State.ToString());
- }
結(jié)果是:
True
Closed
情況:System.Data.CommandBehavior.CloseConnection加完之后,鏈接給你關閉了,為啥?看下面的分析原因。
三:分析原因
1:從前面的兩個示例上看,區(qū)別是什么?
答:區(qū)別就在于一個只讀數(shù)據(jù),另一個綁定了數(shù)據(jù)列表控件。
2:為什么綁定了數(shù)據(jù)列表控件就會自動關閉鏈接?
答:這就涉及到數(shù)據(jù)控件綁定機制了,這里給大伙簡單介紹一下:
A:要實現(xiàn)數(shù)據(jù)控件列表綁定,有一個接口是需要實現(xiàn)的:IEnumerable
B:實現(xiàn)DataReader實現(xiàn)此接口的代碼[基類是抽象方法,所以只能到子類SqlDataReader查看]:
- public override IEnumerator GetEnumerator()
- {
- return new DbEnumerator(this, (this._commandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection);
- }
從這代碼里,我們只看到了它把CloseConnection傳進DbEnumerator里了,再進去看一下:
- public DbEnumerator(IDataReader reader, bool closeReader)
- {
- if (reader == null)
- {
- throw ADP.ArgumentNull("reader");
- }
- this._reader = reader;
- this.closeReader = closeReader;//此行設置了標志
- }
點進去只看到構(gòu)造函數(shù),并把它賦給this.closeReader屬性,因為DataReader是向前讀方式,所以重點還是要看其中的一個方法MoveNext:
- public bool MoveNext()
- {
- if (this._schemaInfo == null)
- {
- this.BuildSchemaInfo();
- }
- this._current = null;
- if (this._reader.Read())//此方法被調(diào)用一次,就讀一次
- {
- object[] values = new object[this._schemaInfo.Length];
- this._reader.GetValues(values);
- this._current = new DataRecordInternal(this._schemaInfo, values, this._descriptors, this._fieldNameLookup);
- return true;//有數(shù)據(jù)時直接返回,不會執(zhí)行下面的關閉鏈接
- }
- if (this.closeReader)//好,能進行這里,說明上面讀不到數(shù)據(jù),簡說就是數(shù)據(jù)讀完了
- {
- this._reader.Close();//關閉鏈接操作。
- }
- return false;
- }
以上代碼就看我注釋的說明。
C:為什么用DataReader綁定列表控件是耍流氓?
答:因為服務端控件列表渲染出表格的周期通常比較長,所以,只有等到你看到最后結(jié)果列表出來的時候,最后一行數(shù)據(jù)才讀完。
因此鏈接是持續(xù)相當長的處于打開狀態(tài),所以web這種并發(fā)多的情況,狂點幾下,估計就報錯了,鏈接池用滿了。
四:最終結(jié)論是什么?
1:在綁定列表控件時,只要數(shù)據(jù)行讀取完畢,就會自動關閉鏈接。
2:在直接讀取時,不會觸發(fā)綁定相關的讀取,所以不會自動關閉鏈接。
3:在綁定列表控件時,鏈接長期得不到關閉,并發(fā)一來,就掛了,因此大伙就不要耍流氓了。
原文鏈接: http://www.cnblogs.com/cyq1162/archive/2011/04/06/2006412.html