聽全老大的 JDBC 課的時候,聽到一節是講在利用 JDBC 中處理批量更新oracle數據時候的特性,讓我很為 JDBC 的特性感的興奮,利用這個特性可以在批量更新數據的時候不同往常一樣每次都需要傳送完成的 SQL 語句到數據庫中。其中示范代碼如下 : 1 import java.s
聽全老大的JDBC課的時候,聽到一節是講在利用JDBC中處理批量更新oracle數據時候的特性,讓我很為JDBC的特性感的興奮,利用這個特性可以在批量更新數據的時候不同往常一樣每次都需要傳送完成的SQL語句到數據庫中。其中示范代碼如下:
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環境變量 20 String url1 = System.getProperty("JDBC_URL"); 21 if (url1 !=null) 22 url = url1; 23 } catch (Exception e) { 24 //如果是在集成開發環境導入了JDBC的話可以注釋這句 25 } 26 27 // 連接到數據庫用 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 // 查詢 輸出結構集 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的架構,sql server號稱是以C/S模式架構,其實它的前身Sybase DataServer 才是C/S模式關系型的第一款數據庫。既然是C/S模式肯定就包含一個客戶端與數據庫段的交互過程,SQLServer在客戶端使用一種稱為TDS的協議來與服務器的Sqlserver服務器來進行數據庫的交互,
TDS (Table Data Strem)
客戶端使用稱為表格格式數據流 (TDS) 的 SQL Server 專用應用程序級協議來發送 SQL 語句。SQL Server 2000 接受 TDS 的下列版本
SQL Server 2000 的 SQL Server 客戶端組件版的客戶端發送的 TDS 8.0
SQL Server 7.0 版的 SQL Server 客戶端組件版的客戶端發送的 TDS 7.0
SQL Server 6.5、6.0 和 4.21a 中運行 SQL Server 客戶端組件的客戶端所發送的 TDS 4.2
如圖表示
客戶段發送一條 select 之類的T-SQL語句,首先會進過TDS使用ODS(output data strem)來包裝數據之后再發送到服務器端,在服務器端會有一個Net-librales的程序對各種網絡協議進行監聽,不管此時你使用的是tcp/ip還是什么其他的協議,Net-librales會根據連接近來的不同協議進行分類,然后歸類集中監聽、處理數據.。
當數據到達服務器端之后交由SQL引擎來處理,如下圖所表示,
在 SQL Server 7.0 中,絕大多數來自客戶機的功能調用都是通過 RPC(遠程存貯過程控制) 消息進行的(但這不是本文想說明的重點),通常,作為 TDS SQL 語言消息的 SQL 語句直接在編譯一端執行,再經過查詢優化器進行一定的優化處理再將結果通過表達試服務返回給客戶機,
在查詢優化器中每編譯(優化)一條T-SQL語句就會生成其對應的執行計劃就是我們常說的緩存。但是平常在客戶端提交上來的T-SQL 經過TDS的包裝,即使2條T-SQL語句完全也不會生成完全相同的TDS格式的數據流,所以查詢優化器編譯之后會認為是2條不同的執行計劃,所以每次都要去重新編譯再緩存,浪費了不必要的時間。難道sqlserver真的做不到jdbc那樣批量提交的優化功能嗎?
其實在Sqlserver中有一個sp_executesql系統存儲過程,通過使用它就能實現高效率的調用因為:
整型參數按其本身格式指定。不需要轉換為 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 執行字符串更有效。使用 sp_executesql 時,只生成 12 個版本的 INSERT 字符串,每個月的表 1 個。使用 EXECUTE 時,因為參數值不同,每個 INSERT 字符串均是唯一的。盡管兩種方法生成的批處理數相同,但因為 sp_executesql 生成的 INSERT 字符串相似,所以查詢優化程序更有可能反復使用執行計劃
呵呵
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com