以session的save方法為例來看一個簡單、完整的事務流程,如下是程式碼片段:
…………………………………………………………………………
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(customer);//之前已執行個體化好了的一個對象
tx.commit();
…………………………………………………………………………
樣本很簡單,就是向資料庫中插入一條顧客資訊,這是一個最簡單的資料庫事務。在這個簡單的過程中,Hibernate為我們做了一些什麼事情呢?為了更好的觀察,我們將Hibernate的”show_sql”屬性設定為true,然後運行我們的程式,控制台列印出如下資訊:
Hibernate: select max(ID) from CUSTOMER
Hibernate: insert into CUSTOMER (NAME, EMAIL, PASSWORD, PHONE, ADDRESS, SEX, IS_MARRIED, description, BIRTHDAY, REGISTERED_TIME, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
這裡也許看不出什麼端倪來,現在在session.save(customer)後面加一行代碼,輸出這個customer的OID,System.out.println(customer.getId()),再次運行程式,控制台輸出為:
Hibernate: select max(ID) from CUSTOMER
22
Hibernate: insert into CUSTOMER (NAME, EMAIL, PASSWORD, PHONE, ADDRESS, SEX, IS_MARRIED, description, BIRTHDAY, REGISTERED_TIME, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
OID在insert語句之前輸出,這可以說明兩個問題:1.insert語句並不是在執行save的時候發送給資料庫的;2.insert語句是在執行commit的時候發送給資料庫的。結合前面我們所說過的:執行save的時候,Hibernate會首先把對象放入緩衝,然後計劃一條insert語句。一個基本的插入流程就出來了:
1. 判斷所要儲存的執行個體是否已處於持久化狀態,如果不是,則將其置入緩衝;
2. 根據所要儲存的執行個體計劃一條insert sql語句,注意只是計劃,並不執行;
3. 事務提交時執行之前所計劃的insert語句;
後台還列印出了select max(ID) from CUSTOMER,這主要是為了給customer賦予一個OID,因為一般情況下臨時對象的OID是NULL。
接著我們做兩個測試:
1. 將tx.commit();注釋掉,此時控制台沒有列印出insert語句;
2. 將tx.commit()換成session.flush,此時控制太列印出了insert語句,但是資料庫中並沒有添加新的記錄;
通過查閱Hibernate的API可以知道flush方法的主要作用就是清理緩衝,強制資料庫
與Hibernate緩衝同步,以保證資料的一致性。它的主要動作就是向資料庫發送一系列的sql語句,並執行這些sql語句,但是不會向資料庫提交。而commit方法則會首先調用flush方法,然後提交事務。這就是為什麼我們僅僅調用flush的時候記錄並未插入到資料庫中的原因,因為只有提交了事務,對資料庫所做的更新才會被儲存下來。因為commit方法隱式的調用了flush,所以一般我們都不會顯示的調用flush方法。