ORACLE內建的JDBC原始碼解析
最後更新:2017-02-28
來源:互聯網
上載者:User
oracle|原始碼
大凡使用過JDBC連ORACLE的人都會知道這樣一個事實:我們需要的庫檔案classes12.zip存在於$ORACLE_HOME/jdbc/lib目錄下(但仍有部分菜鳥每每在論壇上求此庫檔案,真是辛苦);但很少有人知道ORACLE還為我們準備了使用jdbc的樣本,它存在於 $ORACLE_HOME/jdbc/demo/demo.zip 中。
前一段時間,我學習ORACLE的OOP技術,很受觸動。當時我想:JDBC中一定存在某些OO技術以支援它。很久都沒有找到合適的例子,最後在ORACLE的安裝目錄下找到它。真可謂是:踏破鐵鞋無覓處,得來全不費工夫。
約定:
1、如果出現 java.lang.UnsatisfiedLinkError: do_open,則你需要把 DriverManager.getConnection() 方法的 url 修改成 jdbc:oracle:thin:@127.0.0.1:1521:oradb,具體原因未知;
2、如果出現 java.sql.SQLException: 不支援的字元集: oracle-character-set-852,則你需要把 nls_charset12.zip加入你的工程中(此檔案與 classes12.zip 同目錄);
下面我就把檔案夾 amples\oci8\object-samples下的檔案做一個詳細的功能描述:
1、PersonObject.java
這個例子示範了表 people 中存在ADT欄位 empid,其類型為 PERSON,而且類型 PERSON中存在ADT欄位 home,其類型為 ADDRESS,而且類型 ADDRESS是一個ADT。
如果使用常規SQL語句,其插入語句與在sql/plus中無異,即:使用建構函式嵌套構造。
另有一種方法,使用 STRUCT 的建構函式 STRUCT(StructDescriptor, Connection, Object[]) 構造出一個STRUCT對象,即一個ADT對象。同時,如果有嵌套則需要嵌套構造ADT對象。最後通過 PreparedStatement的 setObject方法指定ADT對象即可。
讀取資料時則採用與上述方法相逆的辦法:如果是簡單類型,則直接讀取;如果是ADT,則使用ResultSet的getObject(),再強制轉換成STRUCT,然後調用STRUCT的getAttributes()方法取得 Object[] 類型資料,如是遞迴。
2、SQLDataExample.java與EmployeeObj.java
此例與1中相似,也是對ADT的處理,不同的是類型沒有嵌套。
比較而言,2比1的代碼簡潔了很多,不過也是付出了代價:為類型 EMPLOYEE 抽象出一個類EmployeeObj,它實現了SQLData介面,並重寫了三個方法(必須的)。
前台的調用比1中的第二種方法簡潔了很多,只需要直接使用PreparedStatement的 setObject方法指定ADT對象即可(不過需要指定其類型為OracleTypes.STRUCT)。讀取時也可直接使用OracleResultSet的getObject()並強制轉換成EmployeeObj對象即可。
真可謂是:有得必有失!!
另,此例中有幾處需要注意的地方:
2.1 EmployeeObj.java中的 import oracle.jdbc2.*; 改成 import oracle.jdbc.*; 原因未知;
2.2 SQLDataExample.java 中的 Dictionary map = conn.getTypeMap(); 改成 java.util.Map map = conn.getTypeMap(); 原因:NOTE: This class(指的是Dictionary) is obsolete. New implementations should implement the Map interface, rather than extendidng this class.(來源:javadoc);
2.3 SQLDataExample.java 中的 pstmt.executeQuery(); 改成 pstmt.executeUpdate(); 更合理些,因為這是更新而非查詢(不改也不會影響功能,只是建議);
3、CustomDatumExample.java與Employee.java
此例與2完全相同。不同的是採用了另外一種抽象技術,並實現了介面CustomDatum 與 CustomDatumFactory,並重寫了二個方法toDatum()與create()。在前台訪問資料時亦有少許不同:採用了OracleResultSet的getCustomDatum()方法並把它強制轉換成Employee。從外觀上看,2中SQLData介面存在於 java.sql.* 包中;而介面CustomDatum 與 CustomDatumFactory則存在於oracle.sql.*包中,可以認為是Oracle公司對自己產品的專門實現。或許有更高的效能、更小的開銷?不過3不如2來得直接,個人認為。
4、ArrayExample.java
從檔案名稱可看出,此樣本示範的是VARRAY類型。
同1,插入亦有兩種方法。一種可直接使用SQL;另外,可使用OraclePreparedStatement的setARRAY方法,構造ARRAY的過程與構造 STRUCT 無異。資料的讀取過程與此相反:先使用OracleResultSet的getARRAY()方法取得ARRAY對象,再調用此對象的getArray()方法並強制轉換成對象數組,然後對此數組操作即可。
5、PersonRef.java與StudentRef.java
不知是不是ORACLE與我們開玩笑,這兩個檔案除了類名不同外,其餘一切相同。
這個例子給我們示範的是對象表的概念。對象表的插入與普通表沒有任何不同,資料的讀取首先體現在其SQL上,需要使用REF函數,然後調用ResultSet的getObject()方法並強制轉換成REF對象,再利用此對象的getValue()並轉換成STRUCT對象,再利用此對象 的getAttributes()方法得到Object[],然後對此數組操作即可。
6、RefClient.java與GenREF.java
This sample demonstrates using REF over two different Sessions.
類GenREF用來封裝REF對象所指向的類型及其二進位內容。程式先Materialize into GenREF,然後在另一會話中De-materialize REF from GenREF,下面就與處理REF相同:利用此對象的getValue()並轉換成STRUCT對象,再利用此對象 的getAttributes()方法得到Object[],然後對此數組操作即可。
7、FileExample.java與PLSQL_FileExample.java
此樣本使用 BFILE 資料類型,Contains a locator(定位器) to a large binary file stored outside the database。資料插入時需要使用函數 bfilename,這個函數需要目錄對象,此對象需要使用create directory mydir來建立(此使用者需具有CREATE ANY DIRECTORY系統許可權)。我曾在這個地方有個大教訓:按著步驟做,可在讀取時總是提示我沒有此目錄!!最後,我把BFILENAME函數的第一個參數(即目錄名)大寫就好了。原因:目錄名在函數中區分大小寫,雖然我們建立它時用的是小寫,可到了資料庫中後就自動變成了大寫。
讀取BFILE類型的資料時,首先通過其getBinaryStream()方法得到二進位的輸入資料流,然後操作這個輸入資料流就可以了。The limitation is your imagination。
PLSQL_FileExample.java實現的功能與上述的相同,只不過所有針對BFILE的操作都是通過調用pl/sql匿名塊來完成的,並使用了OracleCallableStatement。如果沒有必要,使用前者即可。
8、LobExample.java與PLSQL_LobExample.java
此樣本使用了CLOB和BLOB資料類型。
插入資料時,需要分別通過getBinaryOutputStream()和getCharacterOutputStream()得到二進位輸出資料流和字元輸出資料流,然後就是針對此輸出資料流的操作了,與傳統的 java I/O 相同。
讀取資料時,需要分別通過getBinaryStream()和getCharacterStream()得到二進位輸入資料流和字元輸入資料流,然後就是針對此輸入資料流的操作了,與傳統的 java I/O 相同。
PLSQL_LobExample.java實現的功能與上述的相同,只不過所有針對CLOB和BLOB的操作都是通過調用pl/sql匿名塊來完成的,並使用了OracleCallableStatement。如果沒有必要,使用前者即可。
註:7、8的第二個樣本中均使用到了dbms_lob程式包。
上面我僅對ORACLE給我們提供的demo的極小的一部分給出瞭解釋,並加入我自己的看法。我也是想通過這篇文章,起到拋磚引玉的作用,希望廣大網友多對產品的樣本進行分析,從而得到最原汁原味的代碼。
你的意見,我願意聽!! email:zbdlmxc@163.com