一:使用SchemaExport自動創建數據庫表
我相信在此之前大家應該都是用最原始的方法:SQL建立數據庫相關的表,然后再Java寫映射寫配置文件.現在我們學習了hibernate以后就可以用一些偷懶的方式了,我們可以使用SchemaExport自動創建數據庫,建立根據你的對象建立數據庫表。下面我們來看一下具體操作:
首先當然要建好POJO object, XML Mapping File(也可以使用工具根據POJO class建立),配置文件(hibernate.cfg.xml),然后運行下面的Java代碼
- import org.hibernate.cfg.Configuration;
- import org.hibernate.tool.hbm2ddl.SchemaExport;
- public class SchemaUtil {
- public static void main(String[] args) {
- Configuration cfg = new Configuration().configure();
- SchemaExport schemaExport= new SchemaExport(cfg);
- schemaExport.create(false, true);
- }
- }
再看看數據庫,表是不是已經幫你建好了,對於我這樣不熟悉數據庫的人真是太方便了。
二.使用Hibernate操作數據庫需要七個步驟
(1)讀取並解析配置文件
Configuration conf = new Configuration().configure();
(2)讀取並解析映射信息,創建SessionFactory
SessionFactory sf = conf.buildSessionFactory();
(3)打開Session
Session session = sf.openSession();
(4)開始一個事務(增刪改操作必須,查詢操作可選)
Transaction tx = session.beginTransaction();
(5)數據庫操作
session.save(user);//或其它操作
(6)提交事務(回滾事務)
tx.commit();(tx.rollback();)
(7)關閉session
session.close();
下面我們來詳細看一下這七大步驟的API:
Configuration:負責管理Hibernate的配置信息,這些配置信息都是從配置文件hibernate.cfg.xml或者Hibernate.properties讀取的,當然也可以自定義文件名稱,只要在實例化Configuration的時候指定具體的路徑就可以了;他為什么會自動加載hibernate.cfg.xml文件的呢?我們看一下configure源碼就一目了然了
- public Configuration configure() throws HibernateException {
- configure( "/hibernate.cfg.xml" );
- return this;
- }
從這里我們可以看出,在hibernate源碼中,他就是默認的加載hibernate.cfg.xml,當然你也可以指定加載配置文件,Configuration提供了相應的方法:
public Configuration configure(String resource)
public Configuration configure(URL url)
public Configuration configure(File configFile)
SessionFactiory:Configuration的實例會根據當前的配置信息,構造SessionFactory實例。SessionFactory是線程安全的,一般情況下一個應用中一個數據庫共享一個SessionFactory實例。
Hibernate的SessionFactory接口提供Session類的實例,Session類用於完成對數據庫的操作。由於SessionFactory實例是線程安全的(而Session實例不是線程安全的),所以每個操作都可以共用同一個SessionFactory來獲取Session。
Hibernate配置文件分為兩種格式,一種是xml格式的配置文件,另一種是Java屬性文件格式的配置文件,因此構建SessionFactory也有兩種方法,下面分別介紹。
1 . 從XML文件讀取配置信息構建SessionFactory
從XML文件讀取配置信息構建SessionFactory的具體步驟如下。
(1)創建一個Configuration對象,並通過該對象的configure()方法加載Hibernate配置文件,代碼如下。
Configuration config = new Configuration().configure();
(2)完成配置文件和映射文件的加載后,將得到一個包括所有Hibernate運行期參數的Configuration實例,通過Configuration實例的buildSessionFactory()方法可以構建一個惟一的SessionFactory,代碼如下。
SessionFactory sessionFactory = config.buildSessionFactory();
構建SessionFactory要放在靜態代碼塊中,因為它只在該類被加載時執行一次。
2 從Java屬性文件讀取配置信息構建SessionFactory
從Java屬性文件讀取配置信息構建SessionFactory的具體步驟如下。
(1)創建一個Configuration對象,此時Hibernate會默認加載classpath中的配置文件hibernate.properties,代碼如下。
Configuration config = new Configuration();
(2)由於在配置文件中缺少相應的配置映射文件的信息,所以此處需要通過編碼方式加載,這可以通過Configuration對象的
addClass()方法實現,具體代碼如下。
config.addClass(BranchForm.class);
addClass()方法用於加載實體類。
(3)完成配置文件和映射文件的加載后,將得到一個包括所有Hibernate運行期參數的Configuration實例,通過Configuration實例
的buildSessionFactory()方法可以構建一個惟一的SessionFactory,代碼如下。
SessionFactory sessionFactory = config.buildSessionFactory();
Session:一般的持久化方法(CRUD)都是通過Session來調用的,Session是非線程安全的。
Session的創建與關閉 :Session是一個輕量級對象,通常將每個Session實例和一個數據庫事務綁定,也就是每執行一個數據庫事務,都應該先創建一個新的Session實例,在使用Session后,還需要關閉Session。
Session的創建
創建SessionFactory后,就可以通過SessionFactory創建Session實例,通過SessionFactory創建Session實例的代碼如下。
Session session=sessionFactory.openSession();
創建Session后,就可以通過創建的Session進行持久化操作了。
Session的關閉
在創建Session實例后,不論是否執行事務,最后都需要關閉Session實例,釋放Session實例占用的資源。
關閉Session實例的代碼如下:
session.close();
下面來看一下:getCurrentSession 與 openSession() 的區別
1.getCurrentSession創建的session會和綁定到當前線程,而openSession不會。
2 getCurrentSession創建的線程會在事務回滾或事物提交后自動關閉,而openSession必須手動關閉
3. getCurrentSession () 使用當前的session,openSession() 重新建立一個新的session
這里getCurrentSession本地事務(本地事務:jdbc)時 要在配置文件里進行如下設置
* 如果使用的是本地事務(jdbc事務)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事務(jta事務)
<property name="hibernate.current_session_context_class">jta</property>
openSession() 與 getCurrentSession() 有何不同和關聯呢?
在 SessionFactory 啟動的時候,Hibernate 會根據配置創建相應的 CurrentSessionContext,在 getCurrentSession() 被調用的時候,實際被執行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 執行時,如果當前 Session 為空,currentSession 會調用 SessionFactory 的 openSession。所以 getCurrentSession() 對於 Java EE 來說是更好的獲取 Session 的方法。
事務transaction:Hibernate是對JDBC的輕量級對象封裝,Hibernate本身是不具備Transaction處理功能的,Hibernate的Transaction實際上是底層的JDBC Transaction的封裝,或者是JTA Transaction的封裝,下面我們詳細的分析:
Hibernate可以配置為JDBCTransaction或者是JTATransaction,這取決於你在hibernate.properties或者hibernate.cfg.xml中的配置,如果你什么都不配置,默認情況下使用JDBCTransaction,如果你配置為: hibernate.transaction.factory_class =net.sf.hibernate.transaction.JTATransactionFactory
將使用JTATransaction 。
JDBCTransaction究竟是什么東西呢?來看看源代碼就清楚了:
Hibernate3.3.2源代碼中的類 org.hibernate.transaction;.JDBCTransaction:
- public void begin() throws HibernateException {
- ...
- try {
- toggleAutoCommit= jdbcContext.connection().getAutoCommit();
- if ( log.isDebugEnabled() ) {
- log.debug("currentautocommitstatus: " + toggleAutoCommit);
- }
- if (toggleAutoCommit) {
- log.debug("disabling autocommit");
- jdbcContext.connection().setAutoCommit(false);
- }
- } ... }
這是啟動Transaction的方法,看到 connection().setAutoCommit(false) 了嗎?是不是很熟悉? 再來看
- public void commit() throws HibernateException {
- ...
- try {
- commitAndResetAutoCommit();
- log.debug("committed JDBC Connection");
- committed = true;
- if ( callback ) {
- jdbcContext.afterTransactionCompletion( true, this );
- }
- notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
- }... ; }
- commitAndResetAutoCommit方法源碼:
- private void commitAndResetAutoCommit() throws SQLException {
- try {
- jdbcContext.connection().commit();
- }
- finally {
- toggleAutoCommit();
- }}
這是提交方法,看到connection().commit() 了嗎?下面就不用我多說了,這個類代碼非常簡單易懂,通過閱讀使我們明白Hibernate的Transaction都在干了些什么?我現在把用Hibernate寫的例子翻譯成JDBC,大家就一目了然了:
Connection conn = ...; <--- session = sf.openSession();
conn.setAutoCommit(false); <--- tx = session.beginTransactioin(); ... <--- ... conn.commit(); <--- tx.commit(); (對應左邊的兩句)
conn.setAutoCommit(true); conn.close(); <--- session.close();
看明白了吧,Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫無神秘可言,只不過在Hibernate中,Session打開的時候,就會自動conn.setAutoCommit(false),不像一般的JDBC,默認都是true,所以你最后不寫commit也沒有關系,由於Hibernate已經把AutoCommit給關掉了,所以用Hibernate的時候,你在程序中不寫Transaction的話,數據庫根本就沒有反應。