聽全老大的 JDBC 課的時(shí)候,聽到一節(jié)是講在利用 JDBC 中處理批量更新oracle數(shù)據(jù)時(shí)候的特性,讓我很為 JDBC 的特性感的興奮,利用這個(gè)特性可以在批量更新數(shù)據(jù)的時(shí)候不同往常一樣每次都需要傳送完成的 SQL 語句到數(shù)據(jù)庫中。其中示范代碼如下 : 1 import java.s
聽全老大的JDBC課的時(shí)候,聽到一節(jié)是講在利用JDBC中處理批量更新oracle數(shù)據(jù)時(shí)候的特性,讓我很為JDBC的特性感的興奮,利用這個(gè)特性可以在批量更新數(shù)據(jù)的時(shí)候不同往常一樣每次都需要傳送完成的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中呢,沒有這個(gè)實(shí)用的特性嗎,隨后的幾天自己開始注意了以下sql Server的架構(gòu),sql server號稱是以C/S模式架構(gòu),其實(shí)它的前身Sybase DataServer 才是C/S模式關(guān)系型的第一款數(shù)據(jù)庫。既然是C/S模式肯定就包含一個(gè)客戶端與數(shù)據(jù)庫段的交互過程,SQLServer在客戶端使用一種稱為TDS的協(xié)議來與服務(wù)器的Sqlserver服務(wù)器來進(jìn)行數(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 中運(yùn)行 SQL Server 客戶端組件的客戶端所發(fā)送的 TDS 4.2
如圖表示
客戶段發(fā)送一條 select 之類的T-SQL語句,首先會進(jìn)過TDS使用ODS(output data strem)來包裝數(shù)據(jù)之后再發(fā)送到服務(wù)器端,在服務(wù)器端會有一個(gè)Net-librales的程序?qū)Ω鞣N網(wǎng)絡(luò)協(xié)議進(jìn)行監(jiān)聽,不管此時(shí)你使用的是tcp/ip還是什么其他的協(xié)議,Net-librales會根據(jù)連接近來的不同協(xié)議進(jìn)行分類,然后歸類集中監(jiān)聽、處理數(shù)據(jù).。
當(dāng)數(shù)據(jù)到達(dá)服務(wù)器端之后交由SQL引擎來處理,如下圖所表示,
在 SQL Server 7.0 中,絕大多數(shù)來自客戶機(jī)的功能調(diào)用都是通過 RPC(遠(yuǎn)程存貯過程控制) 消息進(jìn)行的(但這不是本文想說明的重點(diǎn)),通常,作為 TDS SQL 語言消息的 SQL 語句直接在編譯一端執(zhí)行,再經(jīng)過查詢優(yōu)化器進(jìn)行一定的優(yōu)化處理再將結(jié)果通過表達(dá)試服務(wù)返回給客戶機(jī),
在查詢優(yōu)化器中每編譯(優(yōu)化)一條T-SQL語句就會生成其對應(yīng)的執(zhí)行計(jì)劃就是我們常說的緩存。但是平常在客戶端提交上來的T-SQL 經(jīng)過TDS的包裝,即使2條T-SQL語句完全也不會生成完全相同的TDS格式的數(shù)據(jù)流,所以查詢優(yōu)化器編譯之后會認(rèn)為是2條不同的執(zhí)行計(jì)劃,所以每次都要去重新編譯再緩存,浪費(fèi)了不必要的時(shí)間。難道sqlserver真的做不到j(luò)dbc那樣批量提交的優(yōu)化功能嗎?
其實(shí)在Sqlserver中有一個(gè)sp_executesql系統(tǒng)存儲過程,通過使用它就能實(shí)現(xiàn)高效率的調(diào)用因?yàn)?font face="Times New Roman">:
整型參數(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 時(shí),只生成 12 個(gè)版本的 INSERT 字符串,每個(gè)月的表 1 個(gè)。使用 EXECUTE 時(shí),因?yàn)閰?shù)值不同,每個(gè) INSERT 字符串均是唯一的。盡管兩種方法生成的批處理數(shù)相同,但因?yàn)?sp_executesql 生成的 INSERT 字符串相似,所以查詢優(yōu)化程序更有可能反復(fù)使用執(zhí)行計(jì)劃
呵呵
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com