带你整理面试过程中关于 Mybatis 底层的相关知识

Posted 南淮北安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你整理面试过程中关于 Mybatis 底层的相关知识相关的知识,希望对你有一定的参考价值。

文章目录

一、什么是 Mybatis ?

Mybatis是一个orm类型的半自动框架,执行了对JDBC的封装,是一个持久层框架,它可以通过XML文件或者注解来配置原生信息,不在需要去做更多繁琐重复的过程,如创建连接,加载驱动!

ORM 思想:
	Object Relational Mappging 对象关系映射
	简单的说:
			就是把数据库表和实体类及实体类的属性对应起来
			让我们可以操作实体类就实现操作数据库表。

称Mybatis是半自动ORM映射工具,是因为在查询关联对象或关联集合对象时,需要手动编写sql来完成。不像Hibernate这种全自动ORM映射工具,Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取。
Hibernate:jpa 是一种规范,规范数据库的操作,底层需要 hibernate 实现

二、Mybatis 优缺点及使用场合

优点

  • 基于SQL语句编译,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
  • 与JDBC相比,减少了50%的代码,消除了JDBC大量冗余的代码,不需要手动开关连接;
  • 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)
  • 能够与Spring很好的集成
  • 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护

缺点

  • SQL语句的编写工作量较大,尤其字段多,关联表多时,对开发人员编写SQL语句的功底有一定要求!
  • SQL语句依赖于数据库,导致数据库的移植性差,不能随意更换数据库。

适用场合:MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案,对性能要求很高,或者需求变化较多的项目,如互联网项目

三、#和$的区别是什么?

(1)$表示拼接 sql 串,通过$可以将语句传入的内容拼接在 sql 中

<!-- 根据名称模糊查询 -->
<select id="findByName" parameterType="string" resultType="mybatis.domain.User">
select * from user where username like '%$value%'
</select>

(2)Mybatis在处理#时,会对sql语句进行预处理,将sql中的#替换为?号,调用PreparedStatementset方法来赋值;

关键就是可以有效的防止SQL注入,提高系统的安全性

四、mappers 映射器对应的Dao接口的工作原理?


我们的 Dao 接口并没有实现类,调用它的时候,具体是怎么执行到我们的 SQL 语句的?

配置文件配置package 标签,会将对应包路径下的所有dao 类注册到 Spring 容器中,当我们通过注解注入这个 dao 接口时,返回的是一个 Dao 接口的代理对象,这个代理对象的处理器是 MapperProxy对象,所以通过@Autowired注入Dao接口的时候,注入的就是这个代理对象,我们调用到Dao接口的方法时,则会调用到MapperProxy对象的invoke()方法。

代理对象会拦截接口方法,根据类的全限定名+方法名,唯一定位到一个 MapperStatement 并调用执行器执行所代表的sql,然后将sql执行结果返回。

Mapper 接口里的方法,不能重载,因为是使用 “全限名+方法名” 的保存和寻找策略

<?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">
<!--namespace确定该方法是在哪个dao接口-->
<mapper namespace="mybatis.dao.UserDao">
    <!--查询所有用户-->
    <!--id 表示方法名称,resultType 表示要封装到哪里去-->
    <select id="findAll" resultType="mybatis.domain.User">
        select * from user
    </select>
    <!--保存用户-->
    <insert id="saveUser" parameterType="mybatis.domain.User">
        insert into user(username,birthday,sex,address)
        values (#username,#birthday,#sex,#address)
    </insert>
</mapper>

Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。

当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个SQL标签,比如<select>、<insert>、<update>、<delete>标签,都会被解析为一个MapperStatement对象

五、Mybatis 的一级和二级缓存

缓存:

将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能。

(1)一级缓存:SqlSession 级别的缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存。
一级缓存在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。
也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

(2)二级缓存:mapper 级别的缓存

MyBatis 的二级缓存是 mapper 级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。多个 SqlSession 去操作同一个 Mapper 的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨SqlSession的。

二级缓存里存的只是数据,不是对象,所以每次读取时,值的地址并不同,谁来给的是内容,相同的内容复制到了新地址中。

(3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。

六、Mybatis 的 Mapper 接口调用要求

(1)Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同

(2) Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同

(3)Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同

(4) Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径

<!--namespace确定该方法是在哪个dao接口-->
<mapper namespace="mybatis.dao.UserDao">
    <!--根据id查询-->
    <select id="findById" parameterType="int" resultType="mybatis.domain.User">
        select * from where id = #uid;
    </select>
</mapper>

七、resultMap 和 resultType

(1)resultType

查询出来的列名和实体类中的属性名一致,该列才可以映射成功。(数据库,实体,查询字段,这些全部都得一一对应)


(2)resultMap

当建立查询的列名和实体类的属性名称不一致时可以使用 resultMap 标签可以建立对应关系,从而实现封装
同时 resultMap 可以实现将查询结果映射为复杂类型的实体类,比如在查询结果映射对象中包括实体类 和 list 实现一对一查询和一对多查询

<resultMap id="userMap" type="mybatis.domain.UserTest">
        <!--主键字段的对应-->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="name"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
</resultMap>

八、Mybatis 实现批量插入

配置useGeneratedKeyskeyProperty就可以批量插入并返回主键了

<insert id="batchInsertCameras" useGeneratedKeys="true" keyProperty="cameraNo">
    insert into camera (chanIndex,cameraName)
    values
    <foreach collection="list" item="c" separator=",">
        (#c.chanIndex,#c.cameraName)
    </foreach>
</insert>

具体可参考:mybatis批量插入并返回主键

以上是关于带你整理面试过程中关于 Mybatis 底层的相关知识的主要内容,如果未能解决你的问题,请参考以下文章

带你整理面试过程中关于Innodb的相关知识点

带你整理面试过程中关于Redis 中的字典及 rehash的相关知识点

带你整理面试过程中关于ARP 协议的相关知识点

带你整理面试过程中关于锁的相关知识点下

带你整理面试过程中关于 Java 中的 异常分类及处理的相关知识

带你整理面试过程中关于多线程中的线程池的相关知识点