深刻淺出mybatis之啓動詳解

深刻淺出mybatis之啓動詳解

MyBatis功能豐富,但使用起來很是簡單明瞭,今天咱們來追蹤一下它的啓動過程。html

目錄

<h2 id="1">如何啓動MyBatis</h2>

咱們知道,SqlSessionFactory是MyBatis中最爲核心的組件,每一個基於MyBatis的應用都是以一個SqlSessionFactory實例爲中心的。SqlSessionFactory的實例能夠經過SqlSessionFactoryBuilder得到,而SqlSessionFactoryBuilder則能夠從XML配置文件或一個預先定製的Configuration實例構建出SqlSessionFactory的實例。 java

1. 從XML配置文件中構建SqlSessionFactory實例

從XML文件中構建SqlSessionFactory實例很是簡單,建議使用類路徑下的資源文件進行配置。也能夠使用任意的輸入流(InputStream)實例,包括字符串形式的文件路徑或者「file://」形式的URL文件路徑來配置。一般,咱們使用MyBatis包含一個名叫Resources的工具類,從classpath路徑下加載資源文件。mysql

  • 從類路徑下的xml配置文件中構建SqlSessionFactory
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);
}
  • 從字符串形式路徑下的xml配置文件中構建SqlSessionFactory
public static void main(String[] args) throws IOException {
    // 從文件系統絕對路徑下的xml配置文件中構建SqlSessionFactory
    FileInputStream is = new FileInputStream("D:/mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
}
  • 從"file://"形式的URL路徑xml配置文件中構建SqlSessionFactory
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

2. 經過Java API構建SqlSessionFactory實例

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);
}

<h2 id="2">如何使用MyBatis</h2>

在構建好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

1. 使用xml映射器

所謂的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());
}

2. 使用註解映射器

使用註解方式映射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配置參數。

<h2 id="3">MyBatis啓動過程</h2>

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

相關文章
相關標籤/搜索