在使用hibernate開發時,遇到最多的就是session與事務,那么他們兩個有什么關系呢?下面我來拋磚引玉:
1、session是hibernate中的以及緩存機制,是用來對數據進行增刪改查的一個東西(具體是什么我也不是很清楚,可以理解為是用來操作數據的)
2、事務是一組操作單元的集合,用的比較多的是conmmit和rollback這兩個方法,前面的提交后面的回滾。
先看下面的兩段代碼:
代碼1:
Configuration config = new Configuration().configure("com/ebookstore/config/hibernate.cfg.xml");
Session session = config.buildSessionFactory().openSession();
Transaction tran=session.beginTransaction();
tran.begin();
session.save(object);
tran.commit();
session.flush();
代碼2:
Configuration config = new Configuration().configure("com/ebookstore/config/hibernate.cfg.xml");
Session session = config.buildSessionFactory().openSession();
Object obj = session.get(dtoclass, id);
session.flush();
代碼1:用到了事務,而代碼二呢沒有,這是怎么原因呢?我們可以從兩個方面去理解:
1、在對數據進行查找時,即使你失敗並不影響數據庫中的數據;在對數據庫進行添加時,那就不同了,當你添加數據失敗時,可能會在數據庫中留下垃圾數據。這是我們就要用到事務,事務他提交失敗時,他就會自動回滾。這樣就不影響數據庫了。
2、在對hibernate框架使用時,你不重新開啟事務的話,你是不能對數據進行增刪改的,因為事務默認為是失敗的,也就是數他一直處於回滾狀態。所以你每次操作都是不成功的!
說了這么多,就是一句話,使用hibernate進行增刪改是要重新開啟事務,使用查詢時可以不用重新開啟事務!
二、
以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方法。