欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
關(guān)于 Java Database Connectivity 您不知道的 5 件事

關(guān)于本系列

您覺(jué)得自己懂 Java 編程?事實(shí)是,大多數開(kāi)發(fā)人員都只領(lǐng)會(huì )到了 Java 平臺的皮毛,所學(xué)也只夠應付工作。在本 系列 中,Ted Neward 深度挖掘 Java 平臺的核心功能,揭示一些鮮為人知的事實(shí),幫助您解決最棘手的編程困難。

目前,許多開(kāi)發(fā)人員把 Java Database Connectivity (JDBC) API 當作一種數據訪(fǎng)問(wèn)平臺,比如 Hibernate 或 SpringMany。然而 JDBC 在數據庫連接中不僅僅充當后臺角色。對于 JDBC,您了解的越多,您的 RDBMS 交互效率就越高。

在本期 5 件事 系列 中,我將向您介紹幾種 JDBC 2.0 到 JDBC 4.0 中新引入的功能。設計時(shí)考慮到現代軟件開(kāi)發(fā)所面臨的挑戰,這些新特性支持應用程序可伸縮性,并提高開(kāi)發(fā)人員的工作效率 — 這是現代 Java 開(kāi)發(fā)人員面臨的兩個(gè)最常見(jiàn)的挑戰。

1. 標量函數

不同的 RDBMS 實(shí)現對 SQL 和/或增值特性(目的是讓程序員的工作更為簡(jiǎn)單)提供不規則的支持。例如,眾所周知,SQL 支持一個(gè)標量運算 COUNT(),返回滿(mǎn)足特定 SQL 過(guò)濾規則的行數(更確切地說(shuō),是 WHERE 謂詞)。除此之外,修改 SQL 返回的值是很棘手的 — 想要從數據庫獲取當前日期和時(shí)間會(huì )使 JDBC 開(kāi)發(fā)人員、甚至最有耐心的程序員發(fā)瘋(甚至是心力憔悴)。

于是,JDBC 規范針對不同的 RDBMS 實(shí)現通過(guò)標量函數提供一定程度的隔離/改寫(xiě)。JDBC 規范包括一系列受支持的操作,JDBC 驅動(dòng)程序應該根據特定數據庫實(shí)現的需要進(jìn)行識別和改寫(xiě)。因此,對于一個(gè)支持返回當前日期和/或時(shí)間的數據庫,時(shí)間查詢(xún)應當如清單 1 那樣簡(jiǎn)單:


清單 1. 當前時(shí)間?
            Connection conn = ...; // get it from someplace            Statement stmt = conn.createStatement();            ResultSet rs = stmt.executeQuery("{CURRENT_DATE()}");            

JDBC API 識別的標量函數完整列表在 JDBC 規范附錄中給出(見(jiàn) 參考資料),但是給定的驅動(dòng)程序或數據庫可能不支持完整列表。您可以使用從 Connection 返回的 DatabaseMetaData 對象來(lái)獲取給定 JDBC 支持的函數,如清單 2 所示:


清單 2. 能為我提供什么?
            Connection conn = ...; // get it from someplace            DatabaseMetaData dbmd = conn.getMetaData();            

標量函數列表是從各種 DatabaseMetaData 方法返回的一個(gè)逗號分隔的 String。例如,所有數值標量由 getNumericFunctions() 調用列出,在結果上執行一個(gè) String.split()瞧! — 即刻出現 equals()-testable 列表。


2. 可滾動(dòng) ResultSets

創(chuàng )建一個(gè) Connection 對象,并用它來(lái)創(chuàng )建一個(gè) Statement,這在 JDBC 中是最常用的。提供給 SQL SELECTStatement 返回一個(gè) ResultSet。然后,通過(guò)一個(gè) while 循環(huán)(和 Iterator 沒(méi)什么不同)得到 ResultSet,直到 ResultSet 為空,循環(huán)體從左到右的每次提取一列。

這整個(gè)操作過(guò)程是如此普遍,近乎神圣:它這樣做只是因為它應該這樣做。唉!實(shí)際上這是完全沒(méi)必要的。

引入可滾動(dòng) ResultSet

許多開(kāi)發(fā)人員沒(méi)有意識到,在過(guò)去的幾年中 JBDC 已經(jīng)有了相當大的增強,盡管這些增強在新版本中已經(jīng)有所反映。 第一次重大增強是在 JDBC 2.0 中,發(fā)生在使用 JDK 1.2 期間。寫(xiě)這篇文章時(shí),JDBC 已經(jīng)發(fā)展到了 JDBC 4.0。

JDBC 2.0 中一個(gè)有趣的增強(盡管常常被忽略)是 ResultSet 的滾動(dòng)功能,這意味著(zhù)您可以根據需要前進(jìn)或者后退,或者兩者均可。這樣做需要一點(diǎn)前瞻性,然而 — JDBC 調用必須指出在創(chuàng )建 Statement 時(shí)需要一個(gè)可以滾動(dòng)的 ResultSet。

驗證 ResultSet 類(lèi)型

如果您懷疑一個(gè)驅動(dòng)程序事實(shí)上可能不支持可滾動(dòng)的 ResultSets,不管 DatabaseMetaData 中是如何寫(xiě)的,您都要調用 getType() 來(lái)驗證 ResultSet 類(lèi)型。當然,如果您是個(gè)偏執的人,您可能也不相信 getType() 的返回值??梢赃@樣說(shuō),如果 getType() 隱瞞關(guān)于 ResultSet 的返回值,它們確實(shí) 要吃定您。

如果底層 JDBC 驅動(dòng)程序支持滾動(dòng),一個(gè)可滾動(dòng)的 ResultSet 將從那個(gè) Statement 返回。但是在請求它之前最好弄清楚驅動(dòng)程序是否支持可滾動(dòng)性。您可以通過(guò) DatabaseMetaData 對象探詢(xún)滾動(dòng)性,如上所述,這個(gè)對象可從任何 Connection 中獲取。

一旦您有了一個(gè) DatabaseMetaData 對象,一個(gè)對 getJDBCMajorVersion() 的調用將會(huì )確定驅動(dòng)程序是否支持 JDBC 規范,至少是 JDBC 2.0 規范。當然一個(gè)驅動(dòng)程序可能會(huì )隱瞞它對給定規范的支持程度,因此為了安全起見(jiàn),用期望得到的 ResultSet 類(lèi)型調用 supportsResultSetType() 方法。(在 ResultSet 類(lèi)上它是一個(gè)常量;稍后我們將對其每個(gè)值進(jìn)行討論。)


清單 3. 可以滾動(dòng)?
            int JDBCVersion = dbmd.getJDBCMajorVersion();            boolean srs = dbmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);            if (JDBCVersion > 2 || srs == true)            {            // scroll, baby, scroll!            }            

請求一個(gè)可滾動(dòng)的 ResultSet

假設您的驅動(dòng)程序回答 “是”(如果不是,您需要一個(gè)新的驅動(dòng)程序或數據庫),您可以通過(guò)傳遞兩個(gè)參數到 Connection.createStatement() 調用來(lái)請求一個(gè)可滾動(dòng)的 ResultSet,如清單 4 所示:


清單 4. 我想要滾動(dòng)!
            Statement stmt = con.createStatement(            ResultSet.TYPE_SCROLL_INSENSITIVE,            ResultSet.CONCUR_READ_ONLY);            ResultSet scrollingRS = stmt.executeQuery("SELECT * FROM whatever");            

在調用 createStatement() 時(shí),您必須特別小心,因為它的第一個(gè)和第二個(gè)參數都是 int 的。(在 Java 5 之前我們不能使用枚舉類(lèi)型?。┤魏?int 值(包括錯誤的常量)對 createStatement() 都有效。

第一個(gè)參數,指定 ResultSet 中期望得到的 “可滾動(dòng)性”,應該是以下 3 個(gè)值之一:

  • ResultSet.TYPE_FORWARD_ONLY:這是默認的,是我們了解且喜歡的流水游標。
  • ResultSet.TYPE_SCROLL_INSENSITIVE:這個(gè) ResultSet 支持向后迭代以及向前迭代,但是,如果數據庫中的數據發(fā)生變化,ResultSet 將不能反映出來(lái)。這個(gè)可滾動(dòng)的 ResultSet 可能是最常用到的類(lèi)型。
  • ResultSet.TYPE_SCROLL_SENSITIVE:所創(chuàng )建的 ResultSet 不但支持雙向迭代,而且當數據庫中的數據發(fā)生變化時(shí)還為您提供一個(gè) “實(shí)時(shí)” 數據視圖。

第二個(gè)參數在下一個(gè)技巧中介紹,稍等片刻。

定向滾動(dòng)

當您從 Statement 獲取一個(gè) ResultSet 后,通過(guò)它向后滾動(dòng)只需調用 previous(),即向后滾動(dòng)一行,而不是向前,就像 next() 那樣。您也可以調用 first() 返回到 ResultSet 開(kāi)頭,或者調用 last() 轉到 ResultSet 的末尾,或者...您自己拿主意。

relative()absolute() 方法也是很有用的:前者移動(dòng)指定數量的行(如果是正數則向前移動(dòng),是負數則向后移動(dòng)),后者移動(dòng) ResultSet 中指定數量的行,不管游標在哪。當然,目前行數是由 getRow() 獲取的。

如果您打算通過(guò)調用 setFetchDirection() 在一個(gè)特定方向進(jìn)行一些滾動(dòng),可以通過(guò)指定方向來(lái)幫助 ResultSet。(無(wú)論向哪個(gè)方向滾動(dòng),對于 ResultSet 都可行,但是預先知道滾動(dòng)方向可以?xún)?yōu)化其數據檢索。)


3. 可更新的 ResultSets

JDBC 不僅僅支持雙向 ResultSet,也支持就地更新 ResultSet。這就是說(shuō),與其創(chuàng )建一個(gè)新 SQL 語(yǔ)句來(lái)修改目前存儲在數據庫中的值,您只需要修改保存在 ResultSet 中的值,之后該值會(huì )被自動(dòng)發(fā)送到數據庫中該行所對應的列。

請求一個(gè)可更新的 ResultSet 類(lèi)似于請求一個(gè)可滾動(dòng)的 ResultSet 的過(guò)程。事實(shí)上,在此您將為 createStatement() 使用第二個(gè)參數。您不需要為第二個(gè)參數指定 ResultSet.CONCUR_READ_ONLY,只需要發(fā)送 ResultSet.CONCUR_UPDATEABLE 即可,如清單 5 所示:


清單 5. 我想要一個(gè)可更新的 ResultSet
            Statement stmt = con.createStatement(            ResultSet.TYPE_SCROLL_INSENSITIVE,            ResultSet.CONCUR_UPDATEABLE);            ResultSet scrollingRS = stmt.executeQuery("SELECT * FROM whatever");            

假設您的驅動(dòng)程序支持可更新光標(這是 JDBC 2.0 規范的另一個(gè)特性,這是大多數 “現實(shí)” 數據庫所支持的),您可以更新 ResultSet 中任何給定的值,方法是導航到該行并調用它的一個(gè) update...() 方法(如清單 6 所示),如同 ResultSetget...()方法。在 ResultSetupdate...() 對于實(shí)際的列類(lèi)型是超負荷的。因此要更改名為 “PRICE” 的浮點(diǎn)列,調用 updateFloat("PRICE")。然而,這樣做只能更新 ResultSet 中的值。為了將該值插入支持它的數據庫中,可以調用 updateRow()。如果用戶(hù)改變調整價(jià)格的想法,調用 cancelRowUpdates() 可以停止所有正在進(jìn)行的更新。


清單 6. 一個(gè)更好的方法
            Statement stmt = con.createStatement(            ResultSet.TYPE_SCROLL_INSENSITIVE,            ResultSet.CONCUR_UPDATEABLE);            ResultSet scrollingRS =            stmt.executeQuery("SELECT * FROM lineitem WHERE id=1");            scrollingRS.first();            scrollingRS.udpateFloat("PRICE", 121.45f);            // ...            if (userSaidOK)            scrollingRS.updateRow();            else            scrollingRS.cancelRowUpdates();            

JDBC 2.0 不只支持更新。如果用戶(hù)想要添加一個(gè)全新的行,不需要創(chuàng )建一個(gè)新 Statement 并執行一個(gè) INSERT,只需要調用 moveToInsertRow(),為每個(gè)列調用 update...(),然后調用 insertRow() 完成工作。如果沒(méi)有指定一個(gè)列值,數據庫會(huì )默認將其看作 SQL NULL(如果數據庫模式不允許該列為 NULL,這可能觸發(fā) SQLException)。

當然,如果 ResultSet 支持更新一行,也必然支持通過(guò) deleteRow() 刪除一行。

差點(diǎn)忘了強調一點(diǎn),所有這些可滾動(dòng)性和可更新性都適用于 PreparedStatement(通過(guò)向 prepareStatement() 方法傳遞參數),由于一直處于 SQL 注入攻擊的危險中,這比一個(gè)規則的 Statement 好很多。


4. Rowsets

既然所有這些功能在 JDBC 中大約有 10 年了,為什么大多數開(kāi)發(fā)人員仍然迷戀向前滾動(dòng) ResultSet 和不連貫訪(fǎng)問(wèn)?

罪魁禍首是可伸縮性。保持最低的數據庫連接是支持大量用戶(hù)通過(guò) Internet 訪(fǎng)問(wèn)公司網(wǎng)站的關(guān)鍵。因為滾動(dòng)和/或更新 ResultSet 通常需要一個(gè)開(kāi)放的網(wǎng)絡(luò )連接,而許多開(kāi)發(fā)人員通常不(或不能)使用這些連接。

幸好,JDBC 3.0 引入另一種解決方案讓您同樣可以做很多之前使用 ResultSet 方可以做的事情,而不需要數據庫連接保持開(kāi)放狀態(tài)。

從概念上講,Rowset 本質(zhì)上是一個(gè) ResultSet,但是它支持連接模型或斷開(kāi)模型,您所需要做的是創(chuàng )建一個(gè) Rowset,將其指向一個(gè) ResultSet,當它完成自我填充之后,將其作為一個(gè) ResultSet,如清單 7 所示:


清單 7. Rowset 取代 ResultSet
            Statement stmt = con.createStatement(            ResultSet.TYPE_SCROLL_INSENSITIVE,            ResultSet.CONCUR_UPDATEABLE);            ResultSet scrollingRS = stmt.executeQuery("SELECT * FROM whatever");            if (wantsConnected)            JdbcRowSet rs = new JdbcRowSet(scrollingRS); // connected            else            CachedRowSet crs = new CachedRowSet(scrollingRS); disconnected            

JDBC 還附帶了 5 個(gè) Rowset 接口 “實(shí)現”(也就是擴展接口)。JdbcRowSet 是一個(gè)連接的 Rowset 實(shí)現;其余 4 個(gè)是斷開(kāi)的:

  • CachedRowSet 只是一個(gè)斷開(kāi)的 Rowset.

  • WebRowSetCachedRowSet 的一個(gè)子集,知道如何將其結果轉換成 XML,并再次轉換回來(lái)。

  • JoinRowSet 是一個(gè) WebRowSet,知道如何形成一個(gè) SQL JOIN,而無(wú)需連接到數據庫。

  • FilteredRowSet 是一個(gè) WebRowSet,知道如何更進(jìn)一步過(guò)濾傳遞回來(lái)的數據,而不需要連接到數據庫。

Rowsets 是完整的 JavaBeans,意味著(zhù)它們支持偵聽(tīng)類(lèi)事件,因此,如果需要,也可以捕捉、檢查并執行對 Rowset 的任何修改。事實(shí)上,如果 Rowset 有自己的 Username、Password、URLDatasourceName 屬性集(這意味著(zhù)它將使用 DriverManager.getConnection() 創(chuàng )建一個(gè)連接)或者 Datasource 屬性集(這很可能由 JNDI 獲?。?,它甚至能管理對數據庫的全部操作。然后,您可以在 Command 屬性中指定要執行的 SQL,調用 execute(),然后處理結果 — 不需要更多的工作。

通常,Rowset 實(shí)現是由 JDBC 驅動(dòng)程序提供的,因此實(shí)際的名稱(chēng)和/或包由您所使用的 JDBC 驅動(dòng)程序決定。從 Java 5 開(kāi)始 Rowset 實(shí)現已經(jīng)是標準版本(standard distribution)的一部分了,因此您只需要創(chuàng )建一個(gè) ...RowsetImpl(),然后讓其運行。(如果您的驅動(dòng)程序不能提供一個(gè)參考實(shí)現,Sun 提供了一個(gè),參見(jiàn) 參考資料 部分的鏈接。)


5. 批量更新

盡管 Rowset 很實(shí)用,但有時(shí)候也不能滿(mǎn)足您的需求,您可能需要返回來(lái)直接編寫(xiě) SQL 語(yǔ)句。在這種情況下,特別是當您面對一大堆工作時(shí),您就會(huì )很感激批量更新功能,可在一個(gè)網(wǎng)絡(luò )往返行程中在數據庫中執行多條 SQL 語(yǔ)句。

要確定 JDBC 驅動(dòng)程序是否支持批量更新,快速調用 DatabaseMetaData.supportsBatchUpdates() 可產(chǎn)生一個(gè)明示支持與否的布爾值。在支持批量更新時(shí)(由一些非 SELECT 標示),所有任務(wù)逐個(gè)排隊然后在某一瞬間同時(shí)得到更新,如清單 8 所示:


清單 8. 讓數據庫進(jìn)行批量更新!
            conn.setAutoCommit(false);            PreparedStatement pstmt = conn.prepareStatement("INSERT INTO lineitems VALUES(?,?,?,?)");            pstmt.setInt(1, 1);            pstmt.setString(2, "52919-49278");            pstmt.setFloat(3, 49.99);            pstmt.setBoolean(4, true);            pstmt.addBatch();            // rinse, lather, repeat            int[] updateCount = pstmt.executeBatch();            conn.commit();            conn.setAutoCommit(true);            

默認必須調用 setAutoCommit(),驅動(dòng)程序會(huì )試圖交付提供給它的每條語(yǔ)句。除此之外,其余代碼都是簡(jiǎn)單易懂的:使用 StatementPreparedStatement 進(jìn)行常見(jiàn) SQL 操作,但是不調用 execute(),而調用 executeBatch(),排隊等候調用而不是立即發(fā)送。

準備好各種語(yǔ)句之后,在數據庫中使用 executeBatch() 觸發(fā)所有的語(yǔ)句,這將返回一組整型值,每個(gè)值保存同樣的結果,好像使用了 executeUpdate() 一樣。

在批量處理的一條語(yǔ)句發(fā)生錯誤的情況下,如果驅動(dòng)程序不支持批量更新,或者批處理中的一條語(yǔ)句返回 ResultSet,驅動(dòng)程序將拋出一個(gè) BatchUpdateException。有時(shí)候,在拋出一個(gè)異常之后,驅動(dòng)程序可能試著(zhù)繼續執行語(yǔ)句。JDBC 規范不能授權某一行為,因此您應該事先試用驅動(dòng)程序,這樣就可以確切地知道它是如何工作的。(當然,您要執行單元測試,確保在錯誤成為問(wèn)題之前發(fā)現它,對吧?)

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JDBC常見(jiàn)面試題集錦
一個(gè)簡(jiǎn)單的 JDBC 包裝器
JDBC板塊精華整理20051226
java jdbc返回結果集條數
JDBC進(jìn)化史---從JDBC1.0到JDBC4.2
JDBC常見(jiàn)面試題(修訂版)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久