詳解Java的JDBC API的存儲(chǔ)過(guò)程與SQL轉(zhuǎn)義語(yǔ)法的使用
正如一個(gè)Connection對(duì)象創(chuàng)建Statement和PreparedStatement對(duì)象,它也創(chuàng)造了CallableStatement對(duì)象這將被用來(lái)執(zhí)行調(diào)用數(shù)據(jù)庫(kù)存儲(chǔ)過(guò)程。
創(chuàng)建CallableStatement對(duì)象:
假設(shè),需要執(zhí)行以下Oracle存儲(chǔ)過(guò)程:
CREATE OR REPLACE PROCEDURE getEmpName (EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END;
注意: 上面已經(jīng)寫(xiě)過(guò)Oracle存儲(chǔ)過(guò)程,但我們正在使用MySQL數(shù)據(jù)庫(kù),寫(xiě)相同的存儲(chǔ)過(guò)程對(duì)于MySQL如下,以EMP數(shù)據(jù)庫(kù)中創(chuàng)建它:
DELIMITER $$ DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$ CREATE PROCEDURE `EMP`.`getEmpName` (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255)) BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END $$ DELIMITER ;
三種類(lèi)型的參數(shù)有:IN,OUT和INOUT。PreparedStatement對(duì)象只使用IN參數(shù)。 CallableStatement對(duì)象可以使用所有的三個(gè)。
這里是每個(gè)定義:
- IN:它的值是在創(chuàng)建SQL語(yǔ)句時(shí)未知的參數(shù)。將值綁定到setXXX()方法的參數(shù)。
- OUT:其值是由它返回的SQL語(yǔ)句提供的參數(shù)。你從OUT參數(shù)的getXXX()方法檢索值。
- INOUT:同時(shí)提供輸入和輸出值的參數(shù)。綁定setXXX()方法的變量,并與getXXX()方法檢索值。
下面的代碼片段顯示了如何使用該Connection.prepareCall()方法實(shí)例化基于上述存儲(chǔ)過(guò)程CallableStatement對(duì)象:
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
String變量的SQL表示存儲(chǔ)過(guò)程,使用參數(shù)占位符。
使用CallableStatement對(duì)象是使用PreparedStatement對(duì)象。必須將值綁定到所有的參數(shù)執(zhí)行該語(yǔ)句之前,否則將收到一個(gè)SQLException。
如果有IN參數(shù),只要按照適用于PreparedStatement對(duì)象相同的規(guī)則和技巧;使用對(duì)應(yīng)于要綁定Java數(shù)據(jù)類(lèi)型的setXXX()方法。
當(dāng)使用OUT和INOUT參數(shù)就必須采用額外CallableStatement方法的registerOutParameter()。registerOutParameter()方法JDBC數(shù)據(jù)類(lèi)型綁定到數(shù)據(jù)類(lèi)型的存儲(chǔ)過(guò)程返回。
一旦調(diào)用存儲(chǔ)過(guò)程,用getXXX()方法的輸出參數(shù)檢索值。這種方法投射SQL類(lèi)型的值檢索到Java數(shù)據(jù)類(lèi)型。
關(guān)閉CallableStatement 對(duì)象:
正如關(guān)閉其他Statement對(duì)象,出于同樣的原因,也應(yīng)該關(guān)閉CallableStatement對(duì)象。
close()方法簡(jiǎn)單的調(diào)用將完成這項(xiàng)工作。如果關(guān)閉了Connection對(duì)象首先它會(huì)關(guān)閉CallableStatement對(duì)象為好。然而,應(yīng)該始終明確關(guān)閉的CallableStatement對(duì)象,以確保正確的清除。
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
cstmt.close();
}
PS:CallableStatement對(duì)象實(shí)例
下面是利用CallableStatement連同下列g(shù)etEmpName()的MySQL存儲(chǔ)過(guò)程的例子:
請(qǐng)確定已經(jīng)在EMP數(shù)據(jù)庫(kù)中創(chuàng)建該存儲(chǔ)過(guò)程??梢允褂肕ySQL查詢(xún)?yōu)g覽器來(lái)完成它。
DELIMITER $$ DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$ CREATE PROCEDURE `EMP`.`getEmpName` (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255)) BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END $$ DELIMITER ;
基于對(duì)環(huán)境和數(shù)據(jù)庫(kù)安裝在前面的章節(jié)中進(jìn)行,這個(gè)范例程式碼已被寫(xiě)入。
復(fù)制下面的例子中JDBCExample.java,編譯并運(yùn)行,如下所示:
//STEP 1. Import required packages
import java.sql.*;
public class JDBCExample {
// JDBC driver name and database URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost/EMP";
// Database credentials
static final String USER = "username";
static final String PASS = "password";
public static void main(String[] args) {
Connection conn = null;
CallableStatement stmt = null;
try{
//STEP 2: Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
//STEP 3: Open a connection
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
//STEP 4: Execute a query
System.out.println("Creating statement...");
String sql = "{call getEmpName (?, ?)}";
stmt = conn.prepareCall(sql);
//Bind IN parameter first, then bind OUT parameter
int empID = 102;
stmt.setInt(1, empID); // This would set ID as 102
// Because second parameter is OUT so register it
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
//Use execute method to run stored procedure.
System.out.println("Executing stored procedure..." );
stmt.execute();
//Retrieve employee name with getXXX method
String empName = stmt.getString(2);
System.out.println("Emp Name with ID:" +
empID + " is " + empName);
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}finally{
//finally block used to close resources
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}// nothing we can do
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}//end finally try
}//end try
System.out.println("Goodbye!");
}//end main
}//end JDBCExample
現(xiàn)在編譯上面的例子如下:
C:>javac JDBCExample.java
當(dāng)運(yùn)行JDBCExample,它會(huì)產(chǎn)生以下結(jié)果:
C:>java JDBCExample
Connecting to database... Creating statement... Executing stored procedure... Emp Name with ID:102 is Zaid Goodbye!
JDBC的SQL轉(zhuǎn)義語(yǔ)法:
轉(zhuǎn)義語(yǔ)法使能夠使用通過(guò)使用標(biāo)準(zhǔn)的JDBC方法和屬性,無(wú)法使用數(shù)據(jù)庫(kù)的某些特性的靈活性。
一般的SQL轉(zhuǎn)義語(yǔ)法格式如下:
{keyword 'parameters'}
這里有以下這些,會(huì)發(fā)現(xiàn)非常有用的,而這樣做的JDBC編程的轉(zhuǎn)義序列:
d, t, ts 關(guān)鍵字:
他們幫助確定日期,時(shí)間和時(shí)間戳記文字。如所知,沒(méi)有兩個(gè)數(shù)據(jù)庫(kù)管理系統(tǒng)是基于時(shí)間和日期的方式相同。此轉(zhuǎn)義語(yǔ)法告訴驅(qū)動(dòng)程序呈現(xiàn)在目標(biāo)數(shù)據(jù)庫(kù)的格式,日期或時(shí)間。實(shí)現(xiàn)例子:
{d 'yyyy-mm-dd'}
其中yyyy=年,mm =月,DD =日。使用這種語(yǔ)法 {d '2009-09-03'}是2009年3月9日。
下面是一個(gè)簡(jiǎn)單的例子說(shuō)明如何插入日期表:
//Create a Statement object
stmt = conn.createStatement();
//Insert data ==> ID, First Name, Last Name, DOB
String sql="INSERT INTO STUDENTS VALUES" +
"(100,'Zara','Ali', {d '2001-12-16'})";
stmt.executeUpdate(sql);
同樣,可以使用以下兩種語(yǔ)法之一,無(wú)論是 t 或 ts:
{t 'hh:mm:ss'}
其中hh=小時(shí),mm=分,ss=秒。使用此語(yǔ)法 {t '13:30:29'}是下午1點(diǎn)三十分29秒.
{ts 'yyyy-mm-dd hh:mm:ss'}
這是上述兩種語(yǔ)法 'd' 和 't' 來(lái)表示時(shí)間戳結(jié)合語(yǔ)法。
escape 關(guān)鍵字:
該關(guān)鍵字標(biāo)識(shí)LIKE子句中使用的轉(zhuǎn)義字符。有用使用SQL通配符%,其中匹配零個(gè)或多個(gè)字符時(shí)。例如:
String sql = "SELECT symbol FROM MathSymbols
WHERE symbol LIKE '\%' {escape ''}";
stmt.execute(sql);
如果使用反斜杠字符()作為轉(zhuǎn)義字符,還必須使用兩個(gè)反斜杠字符在Java字符串字面,因?yàn)榉葱备芤彩且粋€(gè)Java轉(zhuǎn)義字符。
fn 關(guān)鍵字:
此關(guān)鍵字代表在DBMS中使用標(biāo)量函數(shù)。例如,可以使用SQL length函數(shù)計(jì)算GE字符串的長(zhǎng)度:
{fn length('Hello World')}
這將返回11,字符串 'Hello World'的長(zhǎng)度。.
call 關(guān)鍵字:
此關(guān)鍵字是用來(lái)調(diào)用存儲(chǔ)過(guò)程。例如,對(duì)于一個(gè)存儲(chǔ)過(guò)程,需要一個(gè)IN參數(shù),請(qǐng)使用以下語(yǔ)法:
{call my_procedure(?)};
對(duì)于一個(gè)存儲(chǔ)過(guò)程,需要一個(gè)IN參數(shù)并返回一個(gè)OUT參數(shù),使用下面的語(yǔ)法:
{? = call my_procedure(?)};
oj 關(guān)鍵字:
此關(guān)鍵字用來(lái)表示外部聯(lián)接。其語(yǔ)法如下:
{oj outer-join}
外連接表={LEFT| RIGHT| FULL}外連接{表|外連接}的搜索條件。例如:
String sql = "SELECT Employees
FROM {oj ThisTable RIGHT
OUTER JOIN ThatTable on id = '100'}";
stmt.execute(sql);
- 詳解Java的JDBC API中事務(wù)的提交和回滾
- Java編程中使用JDBC API連接數(shù)據(jù)庫(kù)和創(chuàng)建程序的方法
- 在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫(kù)
- java數(shù)據(jù)庫(kù)連接池的特點(diǎn)及步驟
- Java操作數(shù)據(jù)庫(kù)連接池案例講解
- 詳解Java數(shù)據(jù)庫(kù)連接池
- Java數(shù)據(jù)庫(kù)連接池技術(shù)的入門(mén)教程
- Java JDBC API介紹與實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池流程
相關(guān)文章
JAVA統(tǒng)計(jì)字符串中某個(gè)字符出現(xiàn)次數(shù)的方法實(shí)現(xiàn)
本文主要介紹了JAVA統(tǒng)計(jì)字符串中某個(gè)字符出現(xiàn)次數(shù)的方法實(shí)現(xiàn),可以循環(huán)使用String的charAt(int index)函數(shù),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
Springboot實(shí)現(xiàn)發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了Springboot實(shí)現(xiàn)發(fā)送郵件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
JavaMailSender實(shí)現(xiàn)郵箱驗(yàn)證功能
本篇文章主要給大家介紹了JavaMailSender實(shí)現(xiàn)郵箱注冊(cè)驗(yàn)證的功能實(shí)現(xiàn)原理以及其中遇到的問(wèn)題,一起跟著學(xué)習(xí)探討下吧。2017-12-12
Java實(shí)現(xiàn)統(tǒng)計(jì)文檔中關(guān)鍵字出現(xiàn)的次數(shù)
這篇文章主要為大家分享了利用Java語(yǔ)言實(shí)現(xiàn)統(tǒng)計(jì)關(guān)鍵字在文檔中出現(xiàn)的次數(shù)的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05
Java參數(shù)校驗(yàn)中validation和validator的區(qū)別詳解
這篇文章主要介紹了Java參數(shù)校驗(yàn)中validation和validator的區(qū)別詳解,一般對(duì)于復(fù)雜的業(yè)務(wù)參數(shù)校驗(yàn),可以通過(guò)校驗(yàn)類(lèi)單獨(dú)的校驗(yàn)方法進(jìn)行處理,通常對(duì)于一些與業(yè)務(wù)無(wú)關(guān)簡(jiǎn)單的參數(shù)校驗(yàn)可以采用validation和 validator通過(guò)注解的方式實(shí)現(xiàn)校驗(yàn),需要的朋友可以參考下2023-10-10

