Hibernate 3.x 提供多種方式呼叫資料庫預存程序。本文以 MySQL 為例,完整示範從 hbm.xml 映射配置查詢類預存程序,到透過 Session 取得 JDBC Connection 呼叫增/刪/改類預存程序的完整實作流程。
tbl_user (userid, name, blog)<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping resource="com/amigo/proc/model/User.hbm.xml"/>
public class User implements java.io.Serializable {
private String userid;
private String name;
private String blog;
// getter/setter 省略
}
<hibernate-mapping package="com.amigo.proc.model">
<class name="User" table="tbl_user">
<id name="userid" column="userid">
<generator class="assigned"/>
</id>
<property name="name" column="name" type="string"/>
<property name="blog" column="blog" type="string"/>
</class>
<!-- 定義呼叫查詢類預存程序 getUserList() -->
<sql-query name="getUserList" callable="true">
<return alias="user" class="User">
<return-property name="userid" column="userid"/>
<return-property name="name" column="name"/>
<return-property name="blog" column="blog"/>
</return>
{call getUserList()}
</sql-query>
</hibernate-mapping>
關鍵屬性說明:
callable="true":宣告這是預存程序呼叫<return>:定義結果集映射到實體alias:結果集別名,供 return-property 參考{call getUserList()}:JDBC Escape 語法呼叫預存程序public class ProcTest {
public static void main(String[] args) throws Exception {
ProcTest proc = new ProcTest();
Session session = HibernateSessionFactory.getSession();
proc.testProcQuery(session); // 查詢
proc.testProcUpdate(session); // 更新
System.out.println("update successfully");
proc.testProcInsert(session); // 新增
System.out.println("insert successfully");
proc.testProcDelete(session); // 刪除
System.out.println("delete successfully");
session.close();
}
// 1. 查詢類:使用映射檔定義的 named query
private void testProcQuery(Session session) throws Exception {
List list = session.getNamedQuery("getUserList").list();
for (int i = 0; i < list.size(); i++) {
User user = (User) list.get(i);
System.out.print("序號: " + (i+1));
System.out.print(", userid: " + user.getUserid());
System.out.print(", name: " + user.getName());
System.out.println(", blog: " + user.getBlog());
}
}
// 2. 更新類:透過 JDBC CallableStatement
private void testProcUpdate(Session session) throws Exception {
Transaction tx = session.beginTransaction();
Connection con = session.connection(); // 取得底層 JDBC Connection
String procedure = "{call updateUser(?, ?, ?)}";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setString(1, "陳xx");
cstmt.setString(2, "https://www.blogjava.net/sterningChen");
cstmt.setString(3, "sterning");
cstmt.executeUpdate();
tx.commit();
}
// 3. 新增類:同樣透過 Connection + CallableStatement
private void testProcInsert(Session session) throws Exception {
session.beginTransaction();
// 注意:此處使用 PreparedStatement 也可呼叫預存程序 (MySQL 支援)
PreparedStatement st = session.connection().prepareStatement("{call createUser(?, ?, ?)}");
st.setString(1, "amigo");
st.setString(2, "阿蜜果");
st.setString(3, "https://www.wblogjava.net/amigoxie");
st.execute();
session.getTransaction().commit();
}
// 4. 刪除類
private void testProcDelete(Session session) throws Exception {
session.beginTransaction();
PreparedStatement st = session.connection().prepareStatement("{call deleteUser(?)}");
st.setString(1, "amigo");
st.execute();
session.getTransaction().commit();
}
}
| 模式 | 適用場景 | 實作方式 |
|---|---|---|
| 映射檔 sql-query | 查詢類預存程序 (需結果集映射實體) | <sql-query name="..." callable="true"> + session.getNamedQuery() |
| JDBC Connection | 增/刪/改類、複雜參數、需交易控制 | session.connection() → CallableStatement/PreparedStatement |
Session.getNamedQuery(String):取得映射檔定義的命名查詢Session.connection():取得底層 JDBC Connection (Hibernate 3.x 仍支援,4.x+ 建議用 session.doWork() 或 session.doReturningWork())Connection.prepareCall(String):建立 CallableStatement 呼叫預存程序{call proc_name(?,?)}:JDBC Escape 語法,跨資料庫可攜增/刪/改操作必須在交易中進行:session.beginTransaction() → 操作 → tx.commit()。查詢類若無修改可不開交易 (但建議統一管理)。
Hibernate 3.x 透過 hbm.xml 的 sql-query 優雅解決查詢類預存程序映射,並保留 Session.connection() 回溯 JDBC 原生呼叫能力,兼顧 ORM 抽象與底層控制。實務上建議:
sql-query 映射,享受自動結果集映射CallableStatement,參數綁定型別安全session.connection() 已棄用,遷移時需調整