聽全老大的 JDBC 課的時候,聽到一節(jié)是講在利用 JDBC 中處理批量更新oracle數(shù)據(jù)時候的特性,讓我很為 JDBC 的特性感的興奮,利用這個特性可以在批量更新數(shù)據(jù)的時候不同往常一樣每次都需要傳送完成的 SQL 語句到數(shù)據(jù)庫中。其中示范代碼如下 : 1 import java.s
聽全老大的JDBC課的時候,聽到一節(jié)是講在利用JDBC中處理批量更新oracle數(shù)據(jù)時候的特性,讓我很為JDBC的特性感的興奮,利用這個特性可以在批量更新數(shù)據(jù)的時候不同往常一樣每次都需要傳送完成的SQL語句到數(shù)據(jù)庫中。其中示范代碼如下:
1 import java.sql.*; 2 3 publicclass BatchUpdates 4 { 5 publicstaticvoid main(String[] args) 6 { 7 Connection conn =null; 8 Statement stmt =null; 9 PreparedStatement pstmt =null; 10 ResultSet rset =null; 11 int i =0; 12 13 try 14 { 15 DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); 16 17 String url ="jdbc:oracle:oci8:@"; 18 try { 19 //檢查是否配置JDBC環(huán)境變量 20 String url1 = System.getProperty("JDBC_URL"); 21 if (url1 !=null) 22 url = url1; 23 } catch (Exception e) { 24 //如果是在集成開發(fā)環(huán)境導(dǎo)入了JDBC的話可以注釋這句 25 } 26 27 // 連接到數(shù)據(jù)庫用 scott 28 conn = DriverManager.getConnection (url, "scott", "tiger"); 29 30 stmt = conn.createStatement(); 31 try { stmt.execute( 32 "create table mytest_table (col1 number, col2 varchar2(20))"); 33 } catch (Exception e1) {} 34 35 // 36 // 批量插入新值. 37 // 38 pstmt = conn.prepareStatement("insert into mytest_table values (?, ?)"); 39 40 pstmt.setInt(1, 1); 41 pstmt.setString(2, "row 1"); 42 pstmt.addBatch(); 43 44 pstmt.setInt(1, 2); 45 pstmt.setString(2, "row 2"); 46 pstmt.addBatch(); 47 48 pstmt.executeBatch(); 49 50 // 51 // 查詢 輸出結(jié)構(gòu)集 52 // 53 rset = stmt.executeQuery("select * from mytest_table"); 54 while (rset.next()) 55 { 56 System.out.println(rset.getInt(1) +", "+ rset.getString(2)); 57 } 58 } 59 catch (Exception e) 60 { 61 e.printStackTrace(); 62 } 63 finally 64 { 65 if (stmt !=null) 66 { 67 try { stmt.execute("drop table mytest_table"); } catch (Exception e) {} 68 try { stmt.close(); } catch (Exception e) {} 69 } 70 if (pstmt !=null) 71 { 72 try { pstmt.close(); } catch (Exception e) {} 73 } 74 if (conn !=null) 75 { 76 try { conn.close(); } catch (Exception e) {} 77 } 78 } 79 } 80 } |
在MSSQLServer中呢,沒有這個實用的特性嗎,隨后的幾天自己開始注意了以下sql Server的架構(gòu),sql server號稱是以C/S模式架構(gòu),其實它的前身Sybase DataServer 才是C/S模式關(guān)系型的第一款數(shù)據(jù)庫。既然是C/S模式肯定就包含一個客戶端與數(shù)據(jù)庫段的交互過程,SQLServer在客戶端使用一種稱為TDS的協(xié)議來與服務(wù)器的Sqlserver服務(wù)器來進行數(shù)據(jù)庫的交互,
TDS (Table Data Strem)
客戶端使用稱為表格格式數(shù)據(jù)流 (TDS) 的 SQL Server 專用應(yīng)用程序級協(xié)議來發(fā)送 SQL 語句。SQL Server 2000 接受 TDS 的下列版本
SQL Server 2000 的 SQL Server 客戶端組件版的客戶端發(fā)送的 TDS 8.0
SQL Server 7.0 版的 SQL Server 客戶端組件版的客戶端發(fā)送的 TDS 7.0
SQL Server 6.5、6.0 和 4.21a 中運行 SQL Server 客戶端組件的客戶端所發(fā)送的 TDS 4.2
如圖表示
客戶段發(fā)送一條 select 之類的T-SQL語句,首先會進過TDS使用ODS(output data strem)來包裝數(shù)據(jù)之后再發(fā)送到服務(wù)器端,在服務(wù)器端會有一個Net-librales的程序?qū)Ω鞣N網(wǎng)絡(luò)協(xié)議進行監(jiān)聽,不管此時你使用的是tcp/ip還是什么其他的協(xié)議,Net-librales會根據(jù)連接近來的不同協(xié)議進行分類,然后歸類集中監(jiān)聽、處理數(shù)據(jù).。
當(dāng)數(shù)據(jù)到達服務(wù)器端之后交由SQL引擎來處理,如下圖所表示,
在 SQL Server 7.0 中,絕大多數(shù)來自客戶機的功能調(diào)用都是通過 RPC(遠程存貯過程控制) 消息進行的(但這不是本文想說明的重點),通常,作為 TDS SQL 語言消息的 SQL 語句直接在編譯一端執(zhí)行,再經(jīng)過查詢優(yōu)化器進行一定的優(yōu)化處理再將結(jié)果通過表達試服務(wù)返回給客戶機,
在查詢優(yōu)化器中每編譯(優(yōu)化)一條T-SQL語句就會生成其對應(yīng)的執(zhí)行計劃就是我們常說的緩存。但是平常在客戶端提交上來的T-SQL 經(jīng)過TDS的包裝,即使2條T-SQL語句完全也不會生成完全相同的TDS格式的數(shù)據(jù)流,所以查詢優(yōu)化器編譯之后會認(rèn)為是2條不同的執(zhí)行計劃,所以每次都要去重新編譯再緩存,浪費了不必要的時間。難道sqlserver真的做不到j(luò)dbc那樣批量提交的優(yōu)化功能嗎?
其實在Sqlserver中有一個sp_executesql系統(tǒng)存儲過程,通過使用它就能實現(xiàn)高效率的調(diào)用因為:
整型參數(shù)按其本身格式指定。不需要轉(zhuǎn)換為 Unicode。
CREATEPROCEDURE InsertSales @PrmOrderIDINT, @PrmCustomerIDINT, -- Build the INSERT statement. /* Set the value to use for the order month because EXEC sp_executesql @InsertString, GO */
比如
CREATETABLE May1998Sales
(OrderID INT PRIMARYKEY,
CustomerID INT NOTNULL,
OrderDate DATETIME NULL
CHECK (DATEPART(yy, OrderDate) =1998),
OrderMonth INT
CHECK (OrderMonth =5),
DeliveryDate DATETIME NULL,
CHECK (DATEPART(mm, OrderDate) = OrderMonth)
)
@PrmOrderDateDATETIME, @PrmDeliveryDateDATETIME
AS
DECLARE@InsertStringNVARCHAR(500)
DECLARE@OrderMonthINT
SET@InsertString='INSERT INTO '+
/* Build the name of the table. */
SUBSTRING( DATENAME(mm, @PrmOrderDate), 1, 3) +
CAST(DATEPART(yy, @PrmOrderDate) ASCHAR(4) ) +
'Sales'+
/* Build a VALUES clause. */
' VALUES (@InsOrderID, @InsCustID, @InsOrdDate,'+
' @InsOrdMonth, @InsDelDate)'
functions are not allowed in the sp_executesql parameter
list. */
SET@OrderMonth=DATEPART(mm, @PrmOrderDate)
N'@InsOrderID INT, @InsCustID INT, @InsOrdDate DATETIME,
@InsOrdMonth INT, @InsDelDate DATETIME',
@PrmOrderID, @PrmCustomerID, @PrmOrderDate,
@OrderMonth, @PrmDeliveryDate
/*
在該過程中使用 sp_executesql 比使用 EXECUTE 執(zhí)行字符串更有效。使用 sp_executesql 時,只生成 12 個版本的 INSERT 字符串,每個月的表 1 個。使用 EXECUTE 時,因為參數(shù)值不同,每個 INSERT 字符串均是唯一的。盡管兩種方法生成的批處理數(shù)相同,但因為 sp_executesql 生成的 INSERT 字符串相似,所以查詢優(yōu)化程序更有可能反復(fù)使用執(zhí)行計劃
呵呵
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com