ORM框架 hibernate和mybatis 鏈接數據詳解

工做中,須要學習一下MyBatis sqlSession的產生過程,翻看了mybatis-spring的源碼,閱讀了一些mybatis的相關doc,對mybatis sqlSession有了一些認知和理解,這裏簡單的總結和整理一下。web

 

    首先, 經過翻閱源碼,咱們來整理一下mybatis進行持久化操做時重要的幾個類:spring

  • SqlSessionFactoryBuilder:build方法建立SqlSessionFactory實例。sql

  • SqlSessionFactory:建立SqlSession實例的工廠。
    安全

  • SqlSession:用於執行持久化操做的對象,相似於jdbc中的Connection。session

  • SqlSessionTemplate:MyBatis提供的持久層訪問模板化的工具,線程安全可經過構造參數或依賴注入SqlSessionFactory實例。
    mybatis

 

    Hibernate是與MyBatis相似的orm框架,這裏與Hibernate進行一下對比,Hibernate中對於connection的管理,是經過如下幾個重要的類:框架

  • SessionFactory:建立Session實例的工廠,相似於MyBatis中的SqlSessionFactory。工具

  • Session:用來執行持久化操做的對象,相似於jdbc中的Connection。
    學習

  • HibernateTemplate:Hibernate提供的持久層訪問模板化的工具,線程安全,可經過構造參數或依賴注入SessionFactory實例。
    ui

 

    在平常的開發中,咱們常常須要這樣對MyBatis和Spring進行集成,把sqlSessionFactory交給Spring管理,一般狀況下,咱們這樣配置:

?

1
2
3
< bean  id = "sqlSessionFactory"  class = "org.mybatis.spring.SqlSessionFactoryBean" >
     < property  name = "dataSource"  ref = "dataSource"  />
</ bean >

    經過上面的配置,Spring將自動建立一個SqlSessionFactory對象,其中使用到了org.mybatis.spring.SqlSessionFactoryBean,其 是MyBatis爲Spring提供的用於建立SqlSessionFactory的類,將在Spring應用程序的上下文建議一下可共享的 MyBatis SqlSessionFactory實例,咱們能夠經過依賴注入將SqlSessionFactory傳遞給MyBatis的一些接口。

 

    若是經過Spring進行事務的管理,咱們須要增長Spring註解的事務管理機制,以下配置:

?

1
2
3
4
5
< bean  id = "transactionManager"  class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
     < property  name = "dataSource"  ref = "dataSource"  />
</ bean >
  
< tx:annotation-driven />

    

    這樣,咱們就可使用Spring @Transactional註解,進行事務的控制,代表所註釋的方法應該在一個事務中運行。 Spring將在事務成功完成後提交事務,在事務發生錯誤時進行異常回滾,並且,Spring會將產生的MyBatis異常轉換成適當的 DataAccessExceptions,從而提供具體的異常信息。

 

    下面,咱們經過分析SqlSessionUtils中getSession的源碼,來詳細的瞭解一下sqlSession的產生過程,源碼以下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public  static  SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
  
   notNull(sessionFactory,  "No SqlSessionFactory specified" );
   notNull(executorType,  "No ExecutorType specified" );
  
   SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
  
   if  (holder !=  null  && holder.isSynchronizedWithTransaction()) {
     if  (holder.getExecutorType() != executorType) {
       throw  new  TransientDataAccessResourceException( "Cannot change the ExecutorType when there is an existing transaction" );
     }
  
     holder.requested();
  
     if  (logger.isDebugEnabled()) {
       logger.debug( "Fetched SqlSession ["  + holder.getSqlSession() +  "] from current transaction" );
     }
  
     return  holder.getSqlSession();
   }
  
   if  (logger.isDebugEnabled()) {
     logger.debug( "Creating a new SqlSession" );
   }
  
   SqlSession session = sessionFactory.openSession(executorType);
  
   // Register session holder if synchronization is active (i.e. a Spring TX is active)
   //
   // Note: The DataSource used by the Environment should be synchronized with the
   // transaction either through DataSourceTxMgr or another tx synchronization.
   // Further assume that if an exception is thrown, whatever started the transaction will
   // handle closing / rolling back the Connection associated with the SqlSession.
   if  (isSynchronizationActive()) {
     Environment environment = sessionFactory.getConfiguration().getEnvironment();
  
     if  (environment.getTransactionFactory()  instanceof  SpringManagedTransactionFactory) {
       if  (logger.isDebugEnabled()) {
         logger.debug( "Registering transaction synchronization for SqlSession ["  + session +  "]" );
       }
  
       holder =  new  SqlSessionHolder(session, executorType, exceptionTranslator);
       bindResource(sessionFactory, holder);
       registerSynchronization( new  SqlSessionSynchronization(holder, sessionFactory));
       holder.setSynchronizedWithTransaction( true );
       holder.requested();
     else  {
       if  (getResource(environment.getDataSource()) ==  null ) {
         if  (logger.isDebugEnabled()) {
           logger.debug( "SqlSession ["  + session +  "] was not registered for synchronization because DataSource is not transactional" );
         }
       else  {
         throw  new  TransientDataAccessResourceException(
             "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization" );
       }
     }
   else  {
     if  (logger.isDebugEnabled()) {
       logger.debug( "SqlSession ["  + session +  "] was not registered for synchronization because synchronization is not active" );
     }
   }
  
   return  session;
}

    上面的getSession方法,會從Spring的事務管理器中獲取一個SqlSession或建立一個新的SqlSession,將試圖從當前事務中獲得一個SqlSession,而後,若是配置有事務管理器的工廠而且Spring 的事務管理器是活躍的,它將會鎖定當前事務的SqlSession,保證同步。主要是經過如下幾個步驟進行SqlSession的建立:

  1. 它會首先獲取SqlSessionHolder,SqlSessionHolder用於在TransactionSynchronizationManager中保持當前的SqlSession。

  2. 若是holder不爲空,而且holder被事務鎖定,則能夠經過holder.getSqlSession()方法,從當前事務中獲取sqlSession,即 Fetched SqlSession from current transaction。

  3. 若是不存在holder或沒有被事務鎖定,則會建立新的sqlSession,即 Creating a new SqlSession,經過sessionFactory.openSession()方法。

  4. 若是當前線程的事務是活躍的,將會爲SqlSession註冊事務同步,即 Registering transaction synchronization for SqlSession。

相關文章
相關標籤/搜索