zoukankan      html  css  js  c++  java
  • 【Mybatis源码解析】- Mybatis入门操作

    Mybatis入门

    MyBatisHibernate一样,是一个优秀的持久层框架。已经说过很多次了,原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装,这样可以让程序员专注于sql语句本身。

    MyBatis通过XML或者注解的方式将要执行的sql语句配置起来,并通过java对象和sql语句映射成最终执行的sql语句。最终由MyBatis框架执行sql,并将结果映射成java对象并返回。

    Mybatis的执行流程

    我们大致了解一下Mybatis的执行流程,结合案例工程来了解一下他是怎么工作的,后面将通过一步步的分析源码的方式进行深一步的了解

    1、读取Mybatis配置信息

    包含全局配置文件和映射文件。全局配置文件包含来数据源、日志、事务等信息,映射文件包含来SQL执行相关的信息

    2、获取SqlSessionFactory工厂

    • 通过XmlConfigBuilder加载配置信息,例如properties外部文件,alias别名,plugins插件等信息
    • 通过XmlMapperBuilder加载Mapper配置文件信息
    • 处理每一个mapper内的信息。
    • 通过XmlStatementBuilder处理标签为select|insert|update|delete的语句,最终调用addMappedStatement方法,将mapper配置文件中的每一条SQL语句封装成mappedStatement对象,作为value保存在HashMap集合中;
    • 下一步执行addLoadedResource使用HashSet集合存放mybatismapper.xml 映射文件路径地址;
    • 进入bindMapperForNamespace()方法,通过namespace使用Java反射机制找到mapper接口,再调用addMapper()方法,判断是否是接口类型,是否注册过(注册过则抛出异常)其中mapperRegistry通过HashMap保存mapper接口,【key:接口;value:MapperProxyFactory】

    3、获取SqlSession

    • 进入openSession()方法,执行newExecutor()方法创建执行器;
    • 先创建 SimpleExecutor简单执行器,再判断是否开启了二级缓存,默认是开启的,就会去创建CacheExecutor缓存执行器
    • 执行interceptorChain.pluginAll()方法,责任链设计模式,底层使用动态代理技术,使开发者可以自定义插件开发,只需要实现Interceptor接口,并指定想要拦截的方法签名即可,最后返回执行器;

    4、操作Mapper接口

    • 调用getMapper()方法,最终执行mapperProxyFactory.newInstance(sqlSession)方法创建代理类MapperProxy
    • 执行MapperProxy代理类的invoke()方法;
    • 判断mapper接口是否有实现类,显然我们没有实现类,则调用cacheMapperMethod()方法去缓存中获取要代理的方法method
    • 进入cacheMapperMethod()方法先去查找缓存中有没有,没有的话将mapper配置文件中配置的SQL语句和对应的mapper接口方法进行关联并放入map缓存中,后期直接走缓存了,最后执行execute()方法;
    • 执行execute()方法,最终调用select*()方法;
    • 进入selectList()方法,调用getMapperStatement()方法获取对应的SQL语句;
    • 执行query()方法进行查询,判断如果开启了二级缓存并且配置了二级缓存存储介质(Redis,EhCache..)则先走二级缓存中查询数据,第一次查询是没有缓存数据的,则刷新缓存配置,清除缓存。
    • 二级缓存(sessionFactory)中没有查询到数据,就回去执行BaseExecutor去查询 HashMap一级缓存中(sqlSession)是否有缓存数据,一级缓存(PerpetualCache)存放在内存中的,同理也是没有的,最后查询数据库DB

    5、封装结果

    案例

    1、数据及Jar包准备

    mybatis组件及mysql驱动

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    

    原始表数据

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for blog
    -- ----------------------------
    DROP TABLE IF EXISTS `person`;
    CREATE TABLE `person` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
        `mobile` varchar(11) COLLATE utf8mb4_general_ci DEFAULT NULL,
        `age` int(2) DEFAULT NULL,
        `email` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    
    -- ----------------------------
    -- Records of blog
    -- ----------------------------
    BEGIN;
    INSERT INTO `person` VALUES (1, 'wujiwen',  '13011111111', 20, 'jiwenwu@outlook.com');
    INSERT INTO `person` VALUES (2, 'mybatis', '13100000000', 10, 'service@mybatis.com');
    COMMIT;
    
    SET FOREIGN_KEY_CHECKS = 1;
    

    2、配置文件信息

    全局配置文件信息mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <properties resource="jdbc.properties"/>
        <typeAliases>
            <typeAlias type="cn.wujiwen.bean.Person" alias="person"/>
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <mapper resource="PersonMapper.xml"/>
        </mappers>
    </configuration>
    

    数据源信息

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/mybatis
    username=root
    password=passw0rd
    

    映射文件Mapper.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="cn.wujiwen.mapper.PersonMapper">
    
        <insert id="insert" parameterType="person" keyColumn="id" keyProperty="id">
            insert into person (nickname,mobile,age,email) values (#{nickname},#{mobile},#{age},#{email});
        </insert>
    
        <update id="update" parameterType="person">
            update person
            <set>
                <if test="nickname != null">
                    nickname = #{nickname},
                </if>
                <if test="mobile != null">
                    mobile = #{mobile},
                </if>
                <if test="age != null">
                    age = #{age},
                </if>
                <if test="email != null">
                    email = #{email},
                </if>
            </set>
            where id = #{id}
        </update>
    
        <delete id="delete">
            delete from person where id = #{id}
        </delete>
        <select id="listPerson" resultType="person">
            select * from person;
        </select>
    
        <select id="getPerson" resultType="person">
            select * from person where id = #{id}
        </select>
    </mapper>
    

    Mapper接口

    
    public interface PersonMapper {
        int insert(Person person);
        int update(Person person);
        int delete(Integer id);
        List<Person> listPerson();
        Person getPerson(Integer id);
    }
    

    测试

    /**
     * Desc:
     *
     * @author wujw
     * @email jiwenwu@outlook.com
     * @date 2021/4/2
     */
    public class MybatisStarted {
    		@Test
        public void test() throws IOException {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = sqlSessionFactory.openSession();
            // 指定key获取sql
            Person person = ((Person) session.selectOne("cn.wujiwen.mapper.PersonMapper.getPerson", 1));
            System.out.println(person);
            
            // 通过代理方式
            PersonMapper mapper = session.getMapper(PersonMapper.class);
            List<Person> personList = mapper.listPerson();
            System.out.println(personList);
        }
    }
    

    作者:黑米面包派

    同步更新: https://www.wujiwen.cn

    欢迎一起交流进步
  • 相关阅读:
    LeetCode90.子集 ||
    Ubuntu下的Matlab安装
    FAQ
    青石板
    交叉熵损失函数
    tf常用函数
    激活函数
    SGD和GD的区别
    卷积神经网络
    Ubuntu安装Matlab2016b
  • 原文地址:https://www.cnblogs.com/wujiwen/p/14714375.html
Copyright © 2011-2022 走看看