Mybatis 的工作原理

Mybatis 工作原理

MyBatis工作原理

上图是Mybatis 工作原理,步骤如下:

  1. 读取 Mybatis 配置文件
    mybatis-config.xml 为 Mybatis 的全局配置文件,配置了 Mybatis 的运行环境等信息,例如数据库连接信息。
  2. 加载映射文件
    映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
  3. 构造会话工厂SqlSessionFactory
    通过 Mybatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
  4. 创建会话对象SqlSession
    由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
  5. Executor 执行器
    Mybatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
  6. MappedStatement 对象
    在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
  7. 输入参数映射
    输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
  8. 输出结果映射
    输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

Mybatis 缓存

Mybatis中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的

  • 一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024 条 SQL。
  • 二级缓存是指可以跨 SqlSession 的缓存,是 mapper 级别的缓存,对于mapper 级别的缓存不同的sqlsession 是可以共享的。


    Mybatis 缓存

Mybatis 的一级缓存原理( sqlsession 级别 )

第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。key:MapperID+offset+limit+Sql+所有的入参
value:用户信息同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。
如果两次中间出现 commit 操作 (修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所 以要从数据库查询,从数据库查询到再写入缓存。

Mybatis 的二级缓存原理 ( mapper 级别)

二级缓存的范围是 mapper 级别(mapper同一个命名空间,Namespace),mapper 以命名空间为单位创建缓存数据结构,结构是 map。
mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。
所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。
key:MapperID+offset+limit+Sql+所有的入参
具体使用需要配置:

  • Mybatis 全局配置中启用二级缓存配置
  • 在对应的 Mapper.xml 中配置 cache 节点
  • 在对应的 select 查询节点中添加 useCache=true

Mybatis 中 #{}和${}的区别是什么

{}是预编译处理,${}是字符串替换。

Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理{}时,就是把{}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
预编译语句的优势在于归纳 为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。

什么是MyBatis的接口绑定?有哪些实现方式?

接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式:

  • 通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;
  • 通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。
    当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

  • 第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。
  • 第二种是使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。
    有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

Mybatis一对一、一对多的查询

  1. MyBatis 中使用collection标签来解决一对多的关联查询
    collection标签可用的属性如下:
    property:指的是集合属性的值.
    ofType:指的是集合中元素的类型.
    column:所对应的外键字段名称.
    select:使用另一个查询封装的结果.
  2. MyBatis 中使用association标签来解决一对一的关联查询
    association标签可用的属性如下:
    property:对象属性的名称.
    javaType:对象属性的类型.
    column:所对应的外键字段名称.
    select:使用另一个查询封装的结果.
<mapper namespace="com.zhxin.logic.system.mapper.userMapper">  
​
    <!--collection  一对多关联查询 -->  
    <select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">  
        select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}  
    </select>  
    <resultMap type="com.zhxin.logic.system.user.Classes" id="ClassesResultMap2">  
        <id property="id" column="c_id"/>  
        <result property="name" column="c_name"/>  
        <association property="teacher" javaType="com.lcb.user.Teacher">  
            <id property="id" column="t_id"/>  
            <result property="name" column="t_name"/>  
        </association>  
        <collection property="student" ofType="com.lcb.user.Student">  
            <id property="id" column="s_id"/>  
            <result property="name" column="s_name"/>  
        </collection>  
    </resultMap>  
    
    <!--association  一对一关联查询 -->  
    <select id="getClass" parameterType="int" resultMap="ClassesResultMap">  
        select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}  
    </select>  
    <resultMap type="com.zhxin.logic.system.user.Classes" id="ClassesResultMap">  
        <!-- 实体类的字段名和数据表的字段名映射 -->  
        <id property="id" column="c_id"/>  
        <result property="name" column="c_name"/>  
        <association property="teacher" javaType="com.lcb.user.Teacher">  
            <id property="id" column="t_id"/>  
            <result property="name" column="t_name"/>  
        </association>  
    </resultMap>  
</mapper>

将sql执行结果封装为目标对象并返回,其实现的过程就是通过resultMap进行封装,而property和 column 进行映射,使数据库的列名和对象的名称对应。Mybatis也会智能匹配,比如可以指定驼峰,如果找不到映射对应的关系,就是默认值

Mybatis的分页原理

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件可以参考:pageHelper、MybatisPlus
分页插件的原理就是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内,拦截待执行的SQL,然后根据设置的dialect(方言),和设置的分页参数,重写SQL ,生成带有分页语句的SQL,执行重写后的SQL,从而实现分页。

//举例:
> select * from student
//拦截sql后重写为
> select t.* from (select * from student)t limit 0,1

什么是Mybatis的动态SQL?

  1. 传统的JDBC的方法,在组合SQL语句的时候需要去拼接,稍微不注意就会少少了一个空格,标点符号,都会导致系统错误。
    Mybatis的动态SQL就是为了解决这种问题而产生的;
    Mybatis的动态SQL语句值基于OGNL表达式的,方便在SQL语句中实现某些逻辑;
    可以使用标签组合成灵活的sql语句,提供开发的效率。
  2. Mybatis的动态SQL标签主要由以下几类:
    If语句(简单的条件判断)
    Choose(when/otherwise),相当于java语言中的switch,与jstl中choose类似 Trim(对包含的内容加上prefix,或者suffix)
    Where(主要是用来简化SQL语句中where条件判断,能智能的处理and/or 不用担心多余的语法导致的错误)
    Set(主要用于更新时候)
    Foreach(一般使用在mybatis in语句查询时特别有用)

总结

具体的Mybatis使用这里提供了一个简单的后台应用EasyAdmin
项目地址:https://gitee.com/kaixinshow/easyadmin

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容