MyBatis功能豐富,但使用起來很是簡單明瞭,今天咱們來追蹤一下它的啓動過程。html
咱們知道,SqlSessionFactory是MyBatis中最爲核心的組件,每一個基於MyBatis的應用都是以一個SqlSessionFactory實例爲中心的。SqlSessionFactory的實例能夠經過SqlSessionFactoryBuilder得到,而SqlSessionFactoryBuilder則能夠從XML配置文件或一個預先定製的Configuration實例構建出SqlSessionFactory的實例。 java
從XML文件中構建SqlSessionFactory實例很是簡單,建議使用類路徑下的資源文件進行配置。也能夠使用任意的輸入流(InputStream)實例,包括字符串形式的文件路徑或者「file://」形式的URL文件路徑來配置。一般,咱們使用MyBatis包含一個名叫Resources的工具類,從classpath路徑下加載資源文件。mysql
public static void main(String[] args) throws IOException { // 使用Resources工具從類路徑下的xml配置中構建SqlSessionFactory String resource = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); }
public static void main(String[] args) throws IOException { // 從文件系統絕對路徑下的xml配置文件中構建SqlSessionFactory FileInputStream is = new FileInputStream("D:/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); }
public static void main(String[] args) throws IOException { // 從URL路徑下的xml配置文件中構建SqlSessionFactory URL url = new URL("file:///D:/mybatis-config.xml"); InputStream is = url.openStream(); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); }
如上所示,咱們從指定路徑下加載MyBatis的配置文件:mybatis-config.xml。固然,正如前面所說,咱們也能夠經過Java API的方式經過定製Configuration類實例來構建SqlSessionFactory實例。sql
public static void main(String[] args) throws IOException { // 經過Java API構建SqlSessionFactory // 數據源 PooledDataSource dataSource = new PooledDataSource(); dataSource.setDriver("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test_mybatis?characterEncoding=utf8&serverTimezone=UTC"); dataSource.setUsername("root"); dataSource.setPassword(""); // 事務管理器 TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("dev", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); // 註冊指定映射器 configuration.addMapper(TestMapper.class); // 註冊映射器類所在包名下的全部映射器 //configuration.addMappers("org.chench.test.mybatis.mapper.impl"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); }
在構建好SqlSessionFactory實例以後,咱們就能夠獲取SqlSession實例,用於與數據庫進行交互。數據庫
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession是一個與數據庫交互的接口,在MyBatis中存在3個實現類,分別是:DefaultSqlSession,SqlSessionManager和SqlSessionTemplate。 其中,DefaultSqlSession是經常使用的SqlSession實現,而SqlSessionManager和SqlSessionTemplate都是SqlSession的代理類,用於實現事務提交和回滾。DefaultSqlSession和SqlSessionManager可用於在普通應用中集成MyBatis,而SqlSessionTemplate則用於MyBatis與Spring框架集成。注意:SqlSessionTemplate本身不實現事務回滾,而是交給Spring框架進行處理,咱們能夠從SqlSessionTemplate的源碼中證明這一點:mybatis
/** * {@inheritDoc} */ @Override public void rollback() { throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); } /** * {@inheritDoc} */ @Override public void rollback(boolean force) { throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); }
獲取到SqlSession實例以後,就能夠執行CRUD操做了。具體來說,對於不用的映射器配置,使用方式略有不一樣。app
所謂的xml映射器是指,將SQL語句及相關ORM映射的配置都寫在xml文件中:框架
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.chench.test.mybatis.mapper"> <!-- 查詢一條數據 --> <select id="selectOneTest" resultType="org.chench.test.mybatis.model.Test"> select * from test where id = #{id} </select> </mapper>
// 從xml映射配置中執行指定id的語句,並傳遞參數 Test test = sqlSession.selectOne("org.chench.test.mybatis.mapper.selectOneTest", 1); if(logger.isDebugEnabled()) { logger.debug((test == null) ? "test is NULL!" : test.toString()); }
使用註解方式映射SQL語句是指:直接將SQL編寫在映射器接口方法的註解中。ide
// 定義映射器接口 public interface TestMapper { // 直接將SQL語句以註解的方式編寫 @Select("select * from test where id = #{id}") public Test selectOneTest(long id); } // 直接調用映射器接口方法,並傳遞參數 Test test = sqlSession.getMapper(TestMapper.class).selectOneTest(1); if(logger.isDebugEnabled()) { logger.debug((test == null) ? "test is NULL!" : test.toString()); }
如上兩種映射器方式分別須要在MyBatis的xml配置文件進行相應的配置,或者在經過Java API方式構建SqlSessionFactory實例時明確進行配置。 mybatis-config.xml:工具
<mappers> <!-- xml映射器:將SQL語句寫在xml文件中 --> <mapper resource="org/chench/test/mybatis/mapper/xml/TestMapper.xml" /> <!-- 註解映射器:將SQL語句寫在Java代碼中, 這裏有2種方式: --> <!-- 方式一: 註冊每個映射器接口,須要明確註冊每個接口 --> <!-- 方式二: 指定映射器接口所在包,則該包下的全部映射器接口都會被註冊 --> <!-- <mapper class="TestMapper" /> --> <package name="org.chench.test.mybatis.mapper.impl"/> </mappers>
注意: 在使用xml配置文件方式構建SqlSessionFactory實例時,既能夠配置xml映射器,也能夠配置註解映射器;可是直接經過Configuration對象構建SqlSessionFactory實例時,只能配置註解映射器。
// 註冊指定註解映射器 configuration.addMapper(TestMapper.class); // 經過映射器類所在包名批量註冊註解映射器 configuration.addMappers("org.chench.test.mybatis.mapper.impl");
差異在於:xml映射器最終會經過XMLConfigBuilder工具類解析爲對應的Configuration配置參數。
SqlSessionFactory既能夠經過xml配置文件構建,也能夠經過Java API構建,那麼它們有什麼區別呢?下面,咱們來一一剖析一下MyBatis的啓動過程。 以從classpath路徑下加載配置文件構建SqlSessionFactory實例的方式提及。
String resource = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
首先,咱們先看一下MyBatis啓動的時序圖:
從上圖咱們能夠很清晰地看到,在MyBatis的啓動過程當中涉及到三個很是核心的類,分別是:SqlSessionFactoryBuilder,XMLConfigBuilder和Configuration,咱們再來進一步追蹤其源碼實現。 SqlSessionFactoryBuilder.java:
// 傳遞配置文件的輸入流對象 public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } // 經過XMLConfigBuilder工具類解析xml配置 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } // 經過Configuration實例構建SqlSessionFactory對象 public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
XMLConfigBuilder.java:
// 調用XMLConfigBuilder工具實例的解析方法,解析xml配置信息,並組裝在Configuration實例屬性中 public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } // 解析MyBatis配置文件,在這裏咱們能夠很清楚的看到MyBatis的配置文件結構 private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
經過上述源碼閱讀咱們不難發現,不論以哪一種方式(xml配置文件或API)構建SqlSessionFactory實例,最終都是經過Configuration實例構建SqlSessionFactory實例。只不過以xml方式配置時,是一種閱讀性更好的方式,可是最終須要經過XMLConfigBuilder工具類對xml配置文件進行解析,而後再構建爲一個Configuration實例。
【參考】 [1]. http://www.mybatis.org/mybatis-3/zh/getting-started.html