顯示具有 Hibernate 標籤的文章。 顯示所有文章
顯示具有 Hibernate 標籤的文章。 顯示所有文章

2007年11月20日 星期二

PostgreSQL Hibernate 連線設定

以下的連線設定以 hibernate 3.0 以上版本為基礎, 除了基本的 hibernate 程式庫, 您還需要下載 PostgreSQL Driver, 才能順利執行.
由於 PostgreSQL 的資料型態與一般的 DB 略為不同, 建議在測試專案時可以將 "hbm2ddl.auto" 這個屬性設為 "true", 讓 hibernate 自動去對應最合適的資料型別, 並自動建立索引, sequence 等服務.

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5432/postgres</property>
<property name="connection.username">inqgen</property>
<property name="connection.password">inqgen</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<mapping resource="inqgen/Person.hbm.xml"/>

</session-factory>

</hibernate-configuration>

2007年8月21日 星期二

Session Level cache

Hibernate 的 session 物件有一種 cache 機制, 可維護一份您存取資料後的 instance.
因為存取資料庫的連線, 需要不小的開銷. 該機制將存取 persistence object 的結果讀進記憶體(利用一份map物件來維護), 若在 session 結束後, 有相同的SQL操作, 則 cache 機制可以直接將物件回傳, 不用再執行額外的資料庫連線動作; 而這種存活於 session 內的 cache 機制, 又稱為 session Level cache.

用一簡例說明:

....
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);
aPerson.getAge();

Person aPerson2 = (Person) session.load(Person.class, personId);
aPerson2.getAge();

session.getTransaction().commit();
session.close();
....

您可以觀察 console 內SQL的執行:
Hibernate: select person0_.PERSON_ID as
PERSON1_2_0_, person0_.age as age2_0_, person0_.firstname as
firstname2_0_, person0_.lastname as lastname2_0_ from PERSON person0_
where person0_.PERSON_ID=?
我們可以發現, 雖然 session.load() 呼叫了兩次, 但由於 cache 機制,
會直接回傳記憶體中的物件給 aPerson2 存取, 如此便減少了一次資料庫的連線成本

但有時存取過於頻繁, cache 內有太多的物件有可能會導致 OutOfMemory,
若您想釋放 cache 中的記憶體, 可以使用 session.clear(), session.evict(object),
另外 session.close() 也會結束該段 cache.

以上例而言:
...
Person aPerson = (Person) session.load(Person.class, personId);
aPerson.getAge();

session.evict(aPerson);
//session.clear()

Person aPerson2 = (Person) session.load(Person.class, personId);
aPerson2.getAge();
...
您會發現 console 會執行兩段SQL指令, 因為 session 中的 cache 已被清除了,session.load()
找不到對應的資料, 就會再重起一段資料連線.

Reference:
Hibernate Gossip: 簡介快取(Session Level)
Reference Documentation

2007年8月5日 星期日

saveOrUpdate 的使用時機

當我們呼叫 session.saveOrUpdate() 時,何時會使用 save(), 何時會使用 update()
取決於物件的id屬性值, 與 hbm.xml 中的 unsaved-value 設定.

Hibernate 會利用該設定的內容, 來比對物件的主鍵屬性.
若主鍵的屬性與 unsaved-value 的設定內容相符(Hibernate 把認為該物件為 Transient Object), 則 Hibernate 送出 session.save(),進行儲存,反之(Hibernate 把認為該物件為 Persistence Object)則呼叫 session.update().

例如:

...
session.beginTransaction();

Person aPerson = new Person();
aPerson.setFirstname("Foo");

Person aPersonUpd = new Person();
aPersonUpd.setId(new Long(2));
aPersonUpd.setFirstname("Foo");

session.saveOrUpdate(aPerson);
session.saveOrUpdate(aPersonUpd);

...
session.getTransaction().commit();
session.close();
若您的 unsaved-value 設為 "null",
而 aPerson 物件的id屬性也為 null, 此時 Hibernate 會執行 session.save(), 資料庫變新增一筆 Person 的紀錄.

另外 aPersonUpd 已設定id為 "2", Hibernate 經由比對後, 若發現資料庫有該筆紀錄, 則會呼叫 session.update() 予以更新.

以下是幾種unsaved-value設定的說明:

1. unsaved-value="null"
為預設的設定, 當取出的物件主鍵值為 null(表示資料庫無對應的紀錄),
則呼叫 save().

2. unsaved-value="undefined"
不論該物件的id屬性塞入任何型態的資料, 都會進行檢查, 若在資料庫中找不到對應的鍵值,
則進行 session.save(), 反之呼叫 session.update().

3. unsaved-value="any"
不論該物件的ID屬性有沒有值, 一定會呼叫 session.save(), 以儲存資料.

4. unsaved-value="none"
不論該物件的ID屬性有沒有值, 一定會呼叫 session.update(), 以更新資料.

若您的主鍵設定為 "assigned" (generator class="assigned"), Hibernate 在判斷時,
會先執行 select 的SQL, 再進行鍵值的比對, 在這種狀況下, 執行 session.saveOrUpdate()
的效能會比 Hibernate的 id generator 略差, 這是值得注意的.

Hibernate 生命週期初探

了解 Hibernate 的物件生命週期, 可以協助您確實的進行資料庫的 CRUD. 而 Hibernate 的物件狀態可分為三種, 如下所示:

1. Transient
該狀態只是簡單的 Value Object, 跟資料庫的記錄沒有任何關聯, 也就是該物件的主鍵(id)不對應任何一筆資料.
例如:

User user = new User();
user.setName("first name");
2. Persistent
當一般的物件納入 Hibernate 的容器管理時, Transient 狀態的物件會轉成 Persistent Object, 直到 Session 物件過期, 或呼叫 session.close().
舉個簡單的例子:

session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);
aPerson.setFirstname("Foo");

session.getTransaction().commit();
session.close();
物件在執行 session.load()(或 get,save)之後, 資料會封裝成物件,
並交給 Hibernate 的容器管理, 此時的狀態也就是 Persistence Object.

以上例, 雖然沒有執行 session.update(), 但是 aPerson 物件從 session.load() 取出後, 已進入 Hibernate的管理機制, 表示跟資料庫的某資筆料相關連了. 因此修改 aPerson.setFirstname(),
再執行 session.getTransaction().commit() 之後, 會修改對應的那一筆資料內容.

3. Detached
若某個物件 Persistence Object 的 session 範圍已經失效, 就進入 Detached 狀態, 與 Value Object 的不同是, Detached 狀態可以再次的關連到 session 的實體.
例如:
Person aPerson = new Person();
aPerson.setFirstname("Foo");
...
session.beginTransaction();
session.save(aPerson);
//Persistence.
...
session.getTransaction().commit();
session.close();
//aPerson物件已變成 Detached 狀態
若此時重起一個 session 實例, 再將 aPersion 封裝進Hibernate的管理容器,
則該物件又會進入 Persistence 的狀態.