動態 SQL 產生


在啟動Hibernate時,預設會為每個實體類別建立SQL語法,問題在於Hibernate如何知道您新增資料時,哪些資料要新增至欄位中,而更新資料時,又如何預先得知要更新哪些欄位?

其實Hibernate並沒有去預測,它所產生的INSERT語法或UPDATE語法,都是對每個欄位進行操作,即使您INSERT時,有些欄位沒有資料,或UPDATE時,只想更新一個,但Hiberntae所產生的SQL則是將舊資料也用UPDATE語法再更新一次。

舉個簡單的例子,在 第 一個 Hibernate 中,如果您使用以下的類別來進行資料新增與更新:
  • HibernateDemo.java
package onlyfun.caterpillar;

import org.hibernate.Session;
import org.hibernate.Transaction;

public class HibernateDemo {
public static void main(String[] args) {
User user = new User();
user.setName("caterpillar");

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx= session.beginTransaction();
session.save(user);
tx.commit();
session.close();

session = HibernateUtil.getSessionFactory().openSession();
tx= session.beginTransaction();
user = (User) session.get(User.class, new Long(1));
user.setAge(new Long(30));
tx.commit();
session.close();

HibernateUtil.shutdown();
}
}

注意到,新增資料時,age屬性並沒有設定,而更新資料時,也只是增加了age屬性的資料,但觀看所產生的SQL:
Hibernate:
    insert
    into
        T_USER
        (name, age)
    values
        (?, ?)
Hibernate:
    select
        user0_.id as id0_0_,
        user0_.name as name0_0_,
        user0_.age as age0_0_
    from
        T_USER user0_
    where
        user0_.id=?
Hibernate:
    update
        T_USER
    set
        name=?,
        age=?
    where
        id=?


SQL中一視同仁的對每個欄位都進行資料的新增或更新,如果您的表格欄位數很多的話,即使只更新一個屬性,卻需要針對每個欄位的內容全部重新更新,顯然對資料庫來說很沒效率。

您可以考慮在HBM中設定Hibernate動態生成SQL,而不是在啟動Hibernate時就生成SQL語法:
  • User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="onlyfun.caterpillar.User" table="T_USER"
dynamic-insert="true"
dynamic-update="true">

<id name="id" column="id">
<generator class="native"/>
</id>

<property name="name" column="name"/>
<property name="age" column="age"/>
</class>
</hibernate-mapping>

設定dynamic-insert與dynamic-update為true後,Hibernate會依據實際要新增或更新的欄位,於執行時期動態產生SQL語法,例如若如上設定,執行同一個程式時,將產生以下的SQL語句:
Hibernate:
    insert
    into
        T_USER
        (name)
    values
        (?, ?)
Hibernate:
    select
        user0_.id as id0_0_,
        user0_.name as name0_0_,
        user0_.age as age0_0_
    from
        T_USER user0_
    where
        user0_.id=?
Hibernate:
    update
        T_USER
    set
        age=?
    where
        id=?


當然,動態判斷哪些欄位需要更新,增加了應用程式本身的負擔,但減輕了資料庫的負擔,建議這種方式只用在於有大量欄位的表格之上。