1. 程式人生 > >Hibernate初始化過程

Hibernate初始化過程

如果要寫一個Hibernate的Hello World程式,我們大概需要做這麼幾件事情:

1. 建立對應表的實體類並編寫其到對應表的對映檔案;

2. 編寫hibernate的配置檔案,預設是hibernate.cfg.xml,你當然可以用其它的名字,只需自己傳遞配置檔名稱給Configure就好;

3. 編寫具體操作資料庫的dataservice;

對於第三步,又可分為:建立SessionFactory;獲取session;通過session物件執行資料庫操作;等等

如Hibernate中一個Tutorial:

  1. public class HibernateUtil {
  2. private
    static final SessionFactory sessionFactory;
  3. static {
  4. try {
  5. // Create the SessionFactory from hibernate.cfg.xml
  6. sessionFactory = new Configuration().configure().buildSessionFactory();
  7. } catch (Throwable ex) {
  8. // Make sure you log the exception, as it might be swallowed
  9. System.err.println("Initial SessionFactory creation failed."
    + ex);
  10. throw new ExceptionInInitializerError(ex);
  11. }
  12. }
  13. public static SessionFactory getSessionFactory() {
  14. return sessionFactory;
  15. }
  16. }

這個工具類中建立了sessionFactory物件,其它的資料服務類都可以使用。(我們應該知道SessionFactory是一個比較“重”的物件,建立的開銷過大,一般一個數據庫使用一個SessionFactory)

  1. protected void doGet(HttpServletRequest request,
    HttpServletResponse response)
  2. throws ServletException, IOException {
  3. ……
  4. try {
  5. // Begin unit of work
  6. HibernateUtil.getSessionFactory()
  7. .getCurrentSession().beginTransaction(); //通過SessionFactory獲取session並開始事務
  8. ……
  9. createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); //資料庫操作
  10. ……
  11. } catch (Exception ex) {
  12. HibernateUtil.getSessionFactory()
  13. .getCurrentSession().getTransaction().rollback(); //異常則回滾事務
  14. throw new ServletException(ex);
  15. }
  16. }
  17. protected void createAndStoreEvent(String title, Date theDate) {
  18. Event theEvent = new Event();
  19. theEvent.setTitle(title);
  20. theEvent.setDate(theDate);
  21. HibernateUtil.getSessionFactory()
  22. .getCurrentSession().save(theEvent); //通過session的save方法儲存物件到資料庫
  23. }

這裡無關的程式碼我都給刪除了,可以看到其流程跟前面提到的第三部基本是一致的。下面便來分析一下這段程式碼的背後,Hibernate做了什麼?整個過程的時序圖如下:

hibernate01

Configuration建構函式中會建立Mapping和SettingsFactory,它們會在後續用於解析SessionFactory的配置屬性,之後呼叫Configuration的configure()函式,在configure()中將通過doConfigure函式完成對Hibernate配置檔案hibernate.cfg.xml的解析。

解析完配置檔案後,便可以通過BuildSessionFactory()建立SessionFactory了,在這個函式中,首先在buildSettings()中通過之前建立的SettingsFactory建立各種屬性設定,之後通過new一個SessionFactoryImpl完成SessionFactory的建立。

有了SessionFactory,Client端便可以通過它獲取Session,並執行各種資料庫操作了。

從getCurrentSession()函式中可以知道,Session是從CurrentSessionContext獲取的,那麼CurrentSessionContext是怎麼來的?可以來看看buildCurrentSessionContext函式的實現:

  1. private CurrentSessionContext buildCurrentSessionContext() {
  2. String impl = this.properties.getProperty("hibernate.current_session_context_class");
  3. if ((impl == null) && (this.transactionManager != null)) {
  4. impl = "jta";
  5. }
  6. if (impl == null) {
  7. return null;
  8. }
  9. if ("jta".equals(impl)) {
  10. if (this.settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions()) {
  11. log.warn("JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()");
  12. }
  13. return new JTASessionContext(this);
  14. }
  15. if ("thread".equals(impl)) {
  16. return new ThreadLocalSessionContext(this);
  17. }
  18. if ("managed".equals(impl)) {
  19. return new ManagedSessionContext(this);
  20. }
  21. try
  22. {
  23. Class implClass = ReflectHelper.classForName(impl);
  24. return ((CurrentSessionContext)implClass.getConstructor(new Class[] { SessionFactoryImplementor.class }).newInstance(new Object[] { this }));
  25. }
  26. catch (Throwable t)
  27. {
  28. log.error("Unable to construct current session context [" + impl + "]", t); }
  29. return null;
  30. }

可以看到,Hibernate會根據“hibernate.current_session_context_class”的屬性值來決定建立哪一類上下文會話(Contextual Session),可以看看Hibernate的參考文件對這個屬性的解釋:“為當前Session的作用域選擇一個自定義策略,可選的會話上下文有:jta|thread|managed|自定義類”。我們以thread型別會話來分析,ThreadLocalSessionContext會藉助ThreadLocal實現每個執行緒有一個對應的session。

有了CurrentSessionContext,來看看getCurrentSession函式:

  1. public Session getCurrentSession()
  2. throws HibernateException
  3. {
  4. if (this.currentSessionContext == null) {
  5. throw new HibernateException("No CurrentSessionContext configured!");
  6. }
  7. return this.currentSessionContext.currentSession();
  8. }

它會通過CurrentSessionContext的currentSession()函式來獲取session,針對ThreadLocalSessionContext,也即:

  1. public final org.hibernate.classic.Session currentSession()
  2. throws HibernateException
  3. {
  4. org.hibernate.classic.Session current = existingSession(this.factory); //檢查ThreadLocal中是否有session,有則直接返回,保證一個執行緒一個session
  5. if (current == null) {
  6. current = buildOrObtainSession(); //通過openSession建立一個新的session
  7. current.getTransaction().registerSynchronization(buildCleanupSynch());
  8. if (needsWrapping(current)) {
  9. current = wrap(current); //包裝session,主要是針對代理的情況
  10. }
  11. doBind(current, this.factory); //當然是把新建的session繫結到ThreadLocal中啦
  12. }
  13. return current;
  14. }

到了這裡,基本就完成了,後面就是通過session執行各種資料操作以及事務管理之類的了。

歡迎關注公眾號: