目的java
MyBatis在執行SQL語句時,都須要建立一個SqlSession,可是這裏還須要與Spring的事務進行整合,那麼SqlSession是怎麼建立的呢?下面就來分析一下。sql
上一章節已經分析MapperProxy代理類中,具體執行代碼,實際MyBatis調用就是使用的SqlSession入口,就來看看SqlSession具體是哪一個類。數據庫
經過DEBUG,可知是SqlSessionTemplate類。session
根據前一章節的查詢來分析,上圖就是SqlSessionTemplate類的查詢方法,就來看一下sqlSessionProxy屬性。app
根據SqlSessionTemplate類的構造器能夠看出,sqlSessionProxy屬性是一個代理類爲SqlSessionInterceptor,看一下代理類的回調方法。spa
明顯這裏有獲取SqlSession,這應該就是DefaultSqlSession,來看看,是怎麼獲取到的?.net
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sessionFactory, "No SqlSessionFactory specified"); notNull(executorType, "No ExecutorType specified"); // 使用Spring來獲取資源 SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory); // 已存在SqlSessionHolder,直接獲取 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 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 + "]"); } // 與Spring綁定 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; }
這裏就是獲取當前的事務裏的SqlSession,並與Spring綁定。debug
DefaultSqlSessionFactory工廠的openSession方法。代理
DefaultSqlSessionFactory工廠的openSessionFromDataSource方法。首先獲取環境信息,獲取事務工廠(SpringManagedTransactionFactory),這個就是在MyBatis整合Spring的實現(1)中4.6建立的。還有Executor也是代理對象,把MyBatis中的配置的攔截器代理進來,這個之後再分析。code
根據數據源(DataSource)建立了一個SpringManagedTransaction事務。
上圖能夠發現,這是個代理對象,最後new DefaultSqlSession對象。
最後經過方法反射調用DefaultSqlSession類的下圖方法。
總結
MyBatis的SqlSession是在Dao層獲取的,Service層只是Spring管理了事務,Dao層MyBatis經過與Spring的整合,來使用Spring的事務,因此目前的配置與Spring的整合,只能支持默認的SIMPLE類型(每次執行一個SQL都須要數據庫編譯),若是須要使用BATCH(批量新增,只需編譯一次SQL,本次添加的SQL都按編譯時的SQL來進行添加),這樣明顯提高效率。批量時,也想使用Spring的事務管理,就須要擴展SqlSession,這裏之後再分析。