• 深入浅出mybatis之启动详解


    深入浅出mybatis之启动详解

    MyBatis功能丰富,但使用起来非常简单明了,今天我们来追踪一下它的启动过程。

    目录

    如何启动MyBatis

    我们知道,SqlSessionFactory是MyBatis中最为核心的组件,每个基于MyBatis的应用都是以一个SqlSessionFactory实例为中心的。SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration实例构建出SqlSessionFactory的实例。

    1. 从XML配置文件中构建SqlSessionFactory实例

    从XML文件中构建SqlSessionFactory实例非常简单,建议使用类路径下的资源文件进行配置。也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者“file://”形式的URL文件路径来配置。通常,我们使用MyBatis包含一个名叫Resources的工具类,从classpath路径下加载资源文件。

    • 从类路径下的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实例。

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

    如何使用MyBatis

    在构建好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的源码中证实这一点:

    /**
     * {@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操作了。具体来讲,对于不用的映射器配置,使用方式略有不同。

    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编写在映射器接口方法的注解中。

    // 定义映射器接口
    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配置参数。

    MyBatis启动过程

    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

  • 相关阅读:
    sp_trace_setfilter sqlserver筛选跟踪或跟踪过滤
    sp_trace_setevent sqlserver跟踪事件及列
    通过导入虚拟电脑的方式还原centos
    sqlserver profiler 抓出来作业的代码 SQLAgent
    克隆server2008R2造成SID冲突
    sqlserver ssms ctrl+e快捷键问题
    Caffe源码解析1:Blob
    梯度下降、随机梯度下降和批量梯度下降
    Caffe CNN特征可视化
    Caffe 抽取CNN网络特征 Python
  • 原文地址:https://www.cnblogs.com/nuccch/p/8466957.html
Copyright © 2020-2023  润新知