1.關(guān)于JDBC
(1)什么是JDBC?
JDBC的全稱是Java Database Connectivity。主要有三個(gè)功能:
a.建立與數(shù)據(jù)庫(kù)的連接和訪問(wèn)任意表格數(shù)據(jù)源。
b.發(fā)送一個(gè)SQL聲明。
c.處理結(jié)果。
(2)連接數(shù)據(jù)庫(kù)的前提
a.安裝jdk。
b.安裝數(shù)據(jù)庫(kù)。
c.下載對(duì)應(yīng)數(shù)據(jù)庫(kù)的驅(qū)動(dòng)。
(3)數(shù)據(jù)庫(kù)驅(qū)動(dòng)的類型
a.驅(qū)動(dòng)實(shí)現(xiàn)JDBC API作為其他數(shù)據(jù)訪問(wèn)API的一種映射,類似ODBC(Open Database Connectivity 開(kāi)放數(shù)據(jù)庫(kù)連接)。這種類型的驅(qū)動(dòng)通常依賴于本地庫(kù),移植性受到很大的限制。如JDBC-ODBC橋接。注意:JDBC-ODBC橋接被認(rèn)為是傳統(tǒng)的解決方案。它不支持Oracle數(shù)據(jù)庫(kù)。使用這個(gè)驅(qū)動(dòng)最好在您的DBMS(數(shù)據(jù)庫(kù)管理系統(tǒng))不提供java的JDBC驅(qū)動(dòng)的情況下。
b.驅(qū)動(dòng)程序編寫部分是Java程序語(yǔ)言,部分是本地代碼。這些驅(qū)動(dòng)程序使用本地客戶端庫(kù)明確它們連接的數(shù)據(jù)源是哪個(gè)。而且,因?yàn)楸镜卮a,移植性也受到了限制。如Oracle的OCI(Oracle Call Interface Oracle回調(diào)接口)客戶端。
c.使用純java的客戶機(jī),使用與數(shù)據(jù)庫(kù)無(wú)關(guān)的協(xié)議和中間服務(wù)器通信。中間件服務(wù)器將主機(jī)的請(qǐng)求和數(shù)據(jù)源進(jìn)行通信。
d.使用純java和實(shí)現(xiàn)了網(wǎng)絡(luò)協(xié)議的驅(qū)動(dòng)程序來(lái)明確數(shù)據(jù)源。客戶端直接和數(shù)據(jù)源連接。
(這個(gè)大家可以看看Java關(guān)于JDBC的文檔。)
2.先在數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)存儲(chǔ)過(guò)程,
(1)先創(chuàng)建包
CREATE OR REPLACE PACKAGE LFF_TEST_PACKAGE
is
PROCEDURE LFF_TEST_PROCEDURE(id in number,org out varchar2,po_fhz out varchar2,po_msg out varchar2);
end LFF_TEST_PACKAGE;1
2
3
4
說(shuō)明:id是number類型的需要傳入的參數(shù),org,po_phz,po_msg是varchar2類型的傳出的參數(shù)。
(2)創(chuàng)建包的實(shí)體
create or replace package body LFF_TEST_PACKAGE as
PROCEDURE LFF_TEST_PROCEDURE(id in number,org out varchar2,po_fhz out varchar2,po_msg out varchar2)
as
--定義其他需要使用的變量,需要指定類型及其大小如 username varchar2(20) 而存儲(chǔ)過(guò)程名稱括號(hào)里面的輸入和輸出參數(shù)是沒(méi)有指定類型大小的
begin
--select * into org from XX where xxx = id;
org := 'aaa';
po_fhz := '1';
po_msg := '調(diào)用成功';
exception
when others then
po_fhz := '-1';
po_msg := '調(diào)用不成功';
end;
end LFF_TEST_PACKAGE;
注意:exception表示出現(xiàn)錯(cuò)誤時(shí)的處理。when others子句用于捕獲命名系統(tǒng)異常和命名的程序員定義異常未處理的所有其余異常。我自己的理解就是相當(dāng)于java中的try{}catch(Exception e){}中的exception。
3.利用JDBC調(diào)用數(shù)據(jù)庫(kù)的存儲(chǔ)過(guò)程。
總的來(lái)說(shuō),執(zhí)行任何JDBC的SQL聲明,有以下幾個(gè)步驟:
(1)建立連接。建立的數(shù)據(jù)連接可以是DBMS,傳統(tǒng)的文件系統(tǒng),或者使用相應(yīng)的JDBC驅(qū)動(dòng)程序的其他數(shù)據(jù)源。在Java API中對(duì)應(yīng)的是Connection類。
(2)創(chuàng)建聲明。在Java API中有三種類型的聲明:
a.Statement:用于不帶參數(shù)實(shí)現(xiàn)簡(jiǎn)單SQL聲明。
b.PreparedStatement:(繼承Statement),用于可以帶有輸入?yún)?shù)的預(yù)編譯SQL聲明。
c.CallableStatement:(繼承PreparedStatement),用于執(zhí)行帶有輸入輸出參數(shù)的存儲(chǔ)過(guò)程。
(3)執(zhí)行語(yǔ)句。Java API中有三種執(zhí)行方法。
a.execute:使用這個(gè)方法可以返回一個(gè)或更多個(gè)結(jié)果集對(duì)象。
b.executeQuery:返回一個(gè)結(jié)果集。用于查詢語(yǔ)句。
c.executeUpdate:返回受到影響的記錄的數(shù)目。這個(gè)方法用于插入insert,刪除delete,或是更新update。
(4)處理結(jié)果集對(duì)象。通過(guò)光標(biāo)處理ResultSet對(duì)象。這個(gè)光標(biāo)不是數(shù)據(jù)庫(kù)中的光標(biāo)。這個(gè)光標(biāo)是一個(gè)指針指向結(jié)果集對(duì)象中的某一行數(shù)據(jù)。最初,這個(gè)光標(biāo)位于第一行數(shù)據(jù)的前面,你可以使用在結(jié)果集ResultSet對(duì)象中定義的各種各樣的方法移動(dòng)光標(biāo)。
(5)關(guān)閉連接。無(wú)論是否拋出異常,在finally中調(diào)用close方法。根據(jù)先打開(kāi)后關(guān)閉的原則。
/**
* @date 2017-6-6
* @author liufeifei
* @description 測(cè)試調(diào)用數(shù)據(jù)庫(kù)的存儲(chǔ)過(guò)程
*/
public class TestProcedure {
public static void main(String[] args) {
//數(shù)據(jù)庫(kù)驅(qū)動(dòng)的名稱
String driver = "oracle.jdbc.OracleDriver";
//訪問(wèn)數(shù)據(jù)庫(kù)路徑 localhost表示本機(jī)(127.0.0.1),xxx表示數(shù)據(jù)庫(kù)名稱
String url = "jdbc:oracle:thin:@localhost:1521:xxx";
//用戶名
String username = "kfxx";
//密碼
String password = "kfxx";
Connection conn = null;
CallableStatement statement = null;
try {
//加載驅(qū)動(dòng)
Class.forName(driver);
//連接
conn = DriverManager.getConnection(url, username, password);
//請(qǐng)求的存儲(chǔ)過(guò)程(包名.存儲(chǔ)過(guò)程名稱,四個(gè)?表示參數(shù))
String sql = "{call LFF_TEST_PACKAGE.LFF_TEST_PROCEDURE(?,?,?,?)}";
statement = conn.prepareCall(sql);
//傳入的參數(shù)
statement.setInt(1,21);
//返回的參數(shù)(oracle.jdbc.OracleTypes.VARCHAR表示返回參數(shù)類型)
statement.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
statement.registerOutParameter(3,oracle.jdbc.OracleTypes.VARCHAR);
statement.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
//執(zhí)行
statement.execute();
//拿到返回的值,我的存儲(chǔ)過(guò)程的參數(shù)1是傳入?yún)?shù),2,3,4是傳出參數(shù)
System.out.println(statement.getString(2) + " "+ statement.getString(3) + " "+ statement.getString(4));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
//關(guān)閉連接
if(statement != null){
statement.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException ex1) {
}
}
}
}
另外,Statement和PreparedStatement的使用:
(1)這三個(gè)都是接口Interface。大家可以去看看JDK的源碼
public interface Statement extends Wrapper {}
public interface PreparedStatement extends Statement {}
public interface CallableStatement extends PreparedStatement {}1
2
3
Statement是用來(lái)執(zhí)行不帶參數(shù)的SQL語(yǔ)句。
Connection conn = null;
ResultSet rs = null;
Statement statement = null;
try {
//加載
Class.forName(driver);
//連接
conn = DriverManager.getConnection(url, username, password);
//設(shè)置查詢語(yǔ)句
statement = conn.createStatement();
statement.execute("select * from emp");
//執(zhí)行查詢
rs = statement.getResultSet();
while(rs.next()){
System.out.println(rs.getObject(2)+"==>"+rs.getObject(1));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
PreparedStatement是用來(lái)執(zhí)行帶輸入?yún)?shù)的SQL語(yǔ)句。
Connection conn = null;
ResultSet rs = null;
PreparedStatement statement = null;
try {
//加載
Class.forName(driver);
//連接
conn = DriverManager.getConnection(url, username,password);
//設(shè)置查詢語(yǔ)句
statement = conn.prepareStatement("select * from emp where ename like ?");
//設(shè)置參數(shù)
statement.setString(1,"%S%");
//執(zhí)行查詢
rs = statement.executeQuery();
while(rs.next()){
System.out.println(rs.getObject(2)+"==>"+rs.getObject(1));
}
}catch(){
}