MARS能在同一條資料連線(SqlConnection)開啟一個以上的結果集,並讓你同時存取這些結果集。
讓我們回憶一下,我們撰寫資料庫的流程,
- 連線字串(SqlConnection)
- SQL定義(SqlCommand)
- 取回資料(DataReader, DataSet)
- 處理(...DataBind...)
- 關閉連線(Close)
不管怎麼寫,大多跳不出這幾個步驟,而如果同一個畫面,同時需要存取幾個DataReader,DataSet,同樣的東西你就要寫兩次,寫三次,這樣是非常沒有效率,這時就非常合適使用MARS技巧。也就是說,步驟1裡的SqlConnection可以同時間給多個SqlCommand來使用,或是說,你需要同時存取同一台Database Server裡的不同資料庫,那也非常合適使用這個MARS技巧。
MARS的設定也異常簡單,只需要在設定連線字串時加入「MultipleActiveResultSets=True」來啟用MARS功能即可。
我們來看一個實例,我們要輸出一個Orders資料表,然後在Orders裡又抓取Orders Details的資料來一起輸出。
無MARS的GridView查詢
以下範例我使用一個下拉式選單,來查詢北風Customers的資料,同時顯示兩個GridView。
GridView.aspx
Imports System.Data Imports System.Data.SqlClient Imports System.Configuration Partial Class GridView Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim ddlconn As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Dim ddlcmd As New SqlCommand ddlcmd.CommandText = "select distinct ContactTitle from customers" ddlcmd.CommandType = CommandType.Text ddlcmd.Connection = ddlconn ddlcmd.Connection.Open() Dim ddldr As SqlDataReader ddldr = ddlcmd.ExecuteReader ddlTitle.DataSource = ddldr '顯示文字所對應資料庫的欄位 ddlTitle.DataTextField = "ContactTitle" '欄位值所對應資料庫的欄位 ddlTitle.DataValueField = "ContactTitle" ddlTitle.DataBind() ddlcmd.Dispose() ddlconn.Dispose() End If End Sub Protected Sub ddlTitle_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlTitle.SelectedIndexChanged '使用DataReader Dim conn As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Dim cmd As New SqlCommand cmd.CommandText = "select top 5 * from customers where ContactTitle=@ContactTitle" cmd.CommandType = CommandType.Text cmd.Connection = conn '參數設定 Dim ContactParam As New SqlParameter ContactParam.ParameterName = "@ContactTitle" '需得選取的值 ContactParam.Value = ddlTitle.SelectedValue cmd.Parameters.Add(ContactParam) cmd.Connection.Open() Dim dr As SqlDataReader 'CommandBehavior.CloseConnection,DataReader自動Close dr = cmd.ExecuteReader(CommandBehavior.CloseConnection) 'DataTable可把DataReader當成資料來源 'Dim drTodt As New DataTable 'drTodt.Load(dr) '由DataTable傳回DataTableReader物件 'Dim dtTodr As DataTableReader 'dtTodr = drTodt.CreateDataReader 'gvDR.DataSource = drTodt 'gvDR.DataSource = dtTodr gvDR.DataSource = dr gvDR.DataBind() 'drTodt.Dispose() 'dtTodr.Close cmd.Dispose() conn.Dispose() '使用DataTable Dim dtconn As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Dim dtcmd As New SqlCommand dtcmd.CommandText = "select top 5 * from customers where ContactTitle=@dtContactTitle order by customerid desc" dtcmd.CommandType = CommandType.Text dtcmd.Connection = dtconn '參數設定 Dim dtContactParam As New SqlParameter dtContactParam.ParameterName = "@dtContactTitle" '取得選取值 dtContactParam.Value = ddlTitle.SelectedValue dtcmd.Parameters.Add(dtContactParam) Dim dap As New SqlDataAdapter Dim dt As New DataTable dap.SelectCommand = dtcmd dap.Fill(dt) gvDT.DataSource = dt.DefaultView gvDT.DataBind() dap.Dispose() dtcmd.Dispose() dtconn.Close() End Sub End Class
你可以看到在SelectedIndexChanged事件裡,我為了要讓兩個GridView顯示不同的資料,所以我必須開關三次SqlConnection(含下拉式控制項的那一次),但其實這是不必要的,接下來我們來看看MARS的使用。
Multiple Active Result Sets
MARS.aspx
<%@ Page Language="VB" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ Import Namespace="System.Configuration" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> '全域連線物件 '在連線字串中必須設定「MultipleActiveResultSets=True」
Dim conn As New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Dim cmd As New SqlCommand Dim OrdersReader As SqlDataReader cmd.CommandText = _ " SELECT TOP 5 Customers.CompanyName, Customers.ContactName, " & _ " Orders.OrderID, Orders.OrderDate, " & _ " Orders.RequiredDate, Orders.ShippedDate " & _ " FROM Orders, Customers " & _ " WHERE Orders.CustomerID = Customers.CustomerID " & _ " ORDER BY Customers.CompanyName, Customers.ContactName " cmd.CommandType = CommandType.Text cmd.Connection = conn conn.Open() OrdersReader = cmd.ExecuteReader() gvOrders.DataSource = OrdersReader gvOrders.DataBind() conn.Close() End Sub ' RowDataBound事件處理常式 Protected Sub gvOrders_RowDataBound(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Dim OrderRecord As IDataRecord Dim lblOrderDetail As Label '從e(DataReader)取得現在連繫的記鍵 '轉換為IDataRecord interface OrderRecord = CType(e.Row.DataItem, IDataRecord) '從GridView物件找到Label控制項 'Label控制項在Order Details裡面 lblOrderDetail = CType(e.Row.FindControl("lblOrderDetail"), Label) If OrderRecord Is Nothing Or lblOrderDetail Is Nothing Then Return End If Dim cmd As New SqlCommand Dim OrderDetailReader As SqlDataReader cmd.CommandText = _ "SELECT Products.ProductName, [Order Details].UnitPrice, " & _ " [Order Details].Quantity, [Order Details].Discount " & _ " FROM [Order Details], Products " & _ " WHERE [Order Details].ProductID = Products.ProductID " & _ " AND [Order Details].OrderID = " + _ Convert.ToString(OrderRecord("OrderID")) cmd.CommandType = CommandType.Text '在連線字串中必須設定「MultipleActiveResultSets=True」 'MARS:Multiple Active Result Sets,多重作用結果集 '注意這裡,我們使用的是同一條SqlConnection來連線,也就是MARS作用所在 cmd.Connection = conn OrderDetailReader = cmd.ExecuteReader() While OrderDetailReader.Read() lblOrderDetail.Text += OrderDetailReader(0).ToString() + " " End While End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>MARS範例</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Label ID="lblCounter" runat="server"> <br />
<asp:GridView ID="gvOrders" runat="server" AutoGenerateColumns="False" OnRowDataBound="gvOrders_RowDataBound" Width="100%"> <Columns> <asp:BoundField HeaderText="Company Name" DataField="CompanyName"></asp:BoundField> <asp:BoundField HeaderText="Contact Name" DataField="ContactName"></asp:BoundField> <asp:TemplateField> <HeaderTemplate> Order Detail </HeaderTemplate> <ItemTemplate> <asp:Label ID="lblOrderDetail" runat="server"> </ItemTemplate> </asp:TemplateField> <asp:BoundField HeaderText="Order Date" DataField="orderdate" DataFormatString="{0:d}"> </asp:BoundField> <asp:BoundField HeaderText="Required Date" DataField="requireddate" DataFormatString="{0:d}"> </asp:BoundField> <asp:BoundField HeaderText="Shipped Date" DataField="shippeddate" DataFormatString="{0:d}"> </asp:BoundField> </Columns> </asp:GridView> <br /> <br /> </div> </form> </body> </html>
範例的重點在71裡RowDataBound事件裡使用同一個SqlConnection物件來連接。MARS在你需要同一Web Form裡需要使用越來越多結果集時,你就可以發現MARS的效果,讓我們的程式更有彈性,更靈活。
請問一下 MultipleActiveResultSets 和 Connection Pool 是一樣的意思嗎
回覆刪除有沒有什麼差異
謝謝