Java|JDBC - Statement、PreparedStatement、CallableStatement

Photo by Ryan Loughlin on Unsplash

 

Statement、PreparedStatement、CallableStatement 皆為 JDBC 中 java.sql 的 interface,用來傳送 SQL 指令給 database,以取得我們所需要的資料(或做其他操作)。

Statement 適用於「通用性的存取(general-purpose access)」(一時想不到其他翻法)。
通常用在 runtime 時使用 static SQL 指令;因該 SQL 指令將會在程式碼中寫死,無法在程式執行(runtime)時由使用者動態提供參數。
例如:SELECT * FROM member WHERE admin = 1
此指令可查閱所有 admin 值為 1 的資料,但這個搜尋條件無法在 runtime 時更改成 admin = 2,因為已在程式碼中被寫死。

PreparedStatement 適用於「希望重複使用該句 SQL 指令」的狀況。
可以在 runtime 時接收參數輸入。
例如:SELECT * FROM member WHERE admin = ?
此指令可在 runtime 時再(由使用者)提供參數(搜尋條件值)至「?」裡。

CallableStatement 適用於「希望存取 database 預存程序(stored procedures)」時。
可以在 runtime 時接收參數輸入。



在使用這三者的功能之前,我們必須先取得與資料庫之間的連線。
在此文中我們要連至 MySQL,版本為 5.1.49。

首先,在讓程式碼易讀的前提下,可以先將所需使用的 parameter 定義出來,包含 database 資訊,如位址、帳號、密碼:
String url = "jdbc:mysql://localhost/3306/company?useUnicode=true&characterEncoding=UTF-8";
String username = "root";
String password = "root";

接著,建立與 database 的連線。
我們使用 JDBC 中 java.sql 的 DriverManager 來建立與 driver 的連線,需要提供它剛剛定義的 database 資訊:
Connection connection = DriverManager.getConnection(url, username, password);
  • getConnection 方法會拋出 SQLException,IDE 會提醒處理,若是使用文字編輯器,記得要自行處理唷!
  • 在 JDBC 3.0(Java 1.5,J2SE 1.4)以前,需先使用 Class.forName("com.mysql.jdbc.Driver"); 來初始化/註冊 Driver
    目前應該都是 JDBC 4.0(Java SE 6)以上,故可省略此步驟
    • 若 MySQL 版本為 6 以上,則為 com.mysql.cj.jdbc.Driver;cj 即為 Connector/J
    • Java SE 8 為 JDBC 4.2;當前最新的 JDBC 版本為 4.3(Java SE 9),發佈於 2017 年

接著,再使用獲得的 connection 來建立 statement,三種各有不同的取得方式:
  • 建立 Statement 不須 parameter
  • 建立 PreparedStatement 及 CallableStatement 需要提供其 SQL 指令(String 型態)
取得 statement 物件後,便可使用他們的功能囉!



Statement

直接藉由 connection 物件建立 statement 物件:
Statement st = connection.createStatement();

boolean execute (String SQL)
若可取得 ResultSet 物件,回傳 true,若否則回傳 false。
適用於 DDL SQL 或需要真正使用 dynamic SQL 時(尚未能理解這點)。

int executeUpdate (String SQL)
回傳影響到的 row 數。通常用於「會更動到 database 資料」時,例如 INSERT、UPDATE、DELETE 指令。

ResultSet executeQuery (String SQL)
回傳 ResultSet 物件。通常用於「查詢」時,例如 SELECT 指令。

最後建議以 close() 方法關閉 statement 物件,以節省 database 資源。
若已先將該 connection 物件關閉,則該 statement 物件會同步被關閉。
st.close();


PreparedStatement

繼承自 Statement,可以有彈性地動態提供參數。

在建立 preparedStatement 物件前,需先定義好 SQL 指令。
String SQL = "UPDATE member SET age = ? WHERE id = ?";
PreparedStatement pst = connection.prepareStatement(SQL);

接著使用 setXXX(int position, XXX value) 方法來設定參數,XXX 對應到該參數的 Java 資料型態。
pst.setInt(1, 30);
pst.setInt(2, 1);
若未設定參數值,會拋出 SQLException。

所有的 statement 物件皆是透過 execute()、executeUpdate()、executeQuery() 與 database 互動。
pst.executeUpdate();

記得,PreparedStatement 繼承自 Statement,故也可以使用可傳入參數的方法。
pst.executeQuery("SELECT * FROM member");

最後,任務完成,記得關掉 statement 物件。
pst.close();


CallableStatement

繼承自 PreparedStatement,用於執行資料庫預存程序(database stored procedure)。

在建立 callableStatement 物件前,需先定義好 SQL 指令。
String SQL = "{CALL getMemberName(?, ?)}";   //傳入 member id,取得 member name
CallableStatement cst = connection.prepareCall(SQL);
  • getMemberName() 為資料庫中的預存程序,在此不贅述。

與 PreparedStatement 一樣,需要對參數值進行設定。
第一個 ? 為 IN parameter,為 member id,資料型態為 Java int,
與 preparedStatement 一樣使用 setXXX() 進行設定。
第二個 ? 為 OUT parameter,為 member name,資料型態為 MySQL VARCHAR,
需使用 callableStatement 的 registerOutParameter() 進行設定。
關於預存程序(stored procedure)、IN、OUT、INOUT parameter,可參 MySQL Stored Procedure Parameters

CallableStatement 亦為 Statement 物件,故也是使用 execute()、executeUpdate()、executeQuery() 與 database 互動及取得結果。




StatementPreparedStatementCallableStatement
建立
方式
不須參數
connection.createStatement()
需提供參數 (String SQL)
connection.prepareStatement(SQL)
需提供參數 (String SQL)
connection.prepareCall(SQL)
執行
方法
boolean execute (String SQL)
int executeUpdate (String SQL)
ResultSet executeQuery (String SQL)
先以 setXXX () 設定參數條件值
boolean execute ()
int executeUpdate ()
ResultSet executeQuery ()
先以 setXXX() 或 registerOutParameter() 設定參數
boolean execute ()
int executeUpdate ()
ResultSet executeQuery ()




- References -



留言