mybatis面试题

  1. #{} 和 \({} 区别是什么(\)读 dollar [ˈdɑːlər])
    #{}是预编译处理,${}是字符串替换。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理${}时,就是把${}替换成变量的值。 使用#{}可以有效的防止SQL注入,提高系统安全性。
    之前面试问过这个点,我按以上回答被打断了,它说区别就是#{}会将参数加上引号。这也是一个点,虽然不是完全正确,待补充加上引号的条件。

  2. 实体类属性名称和表字段名不一致怎么办
    一般都使用定义resultMap来处理属性名和字段名的映射。
    还可以在sql中使用别名,不过用的比较少
    《阿里巴巴开发手册》强制不直接使用 resultClass 进行映射返回,也即需要定义 resultMap

  3. 模糊查询sql如何写

    1. select * from table where filed like #{param},然后事先在入参中拼接好通配符(%、_)
    2. select * from table where filed like "%"#{param}"%",在SQL中使用"%"、"_",注意需要使用引号
    3. select * from table where filed like "%${param}%",注意和第二种拼写区别,存在SQL注入问题
    4. select * from table where filed like concat("%", #{param}, "%")
    5. select * from table where filed like concat("%", "${param}", "%"),注意需要使用引号
  4. DAO 与 XML 配置文件映射原理?DAO 中的方法能重载吗?

    1. DAO 与 XML 是通过类全限定名匹配的,也即 xml 的 namespace 为对应类全限定名
    2. xml 中的每条 sql 的 id 对应 DAO 的方法,由于 id 即为方法名,因此 DAO 的方法不能重载
    3. 在Mybatis中,每一个标签,都会被解析为一个MapperStatement对象,Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回
  5. MyBatis 是如何进行分页的?MyBatis分页插件原理

    1. 本地提供了 RowBounds 进行分页(没使用过),利用 JDBC 驱动中的 ResultSet 结果集进行分页,不是完全的内存分页,也即不是全部加载入内存,然后 subList 截取一部分那种
    2. sql 中使用 limit 分页
    3. 分页插件分页,使用 MyBatis 提供的拦截器扩展 Interceptor,重写 sql,添加 limit 语句(根据dialect方言,添加对应的物理分页语句和物理分页参数)
  6. 如何批量插入

    1. 代码 foreach 插入,一般不使用,效率低
    2. 动态 sql, <foreach> 标签拼接插入,一般使用的都是这个
    3. executortype.batch 批量插入
    4. ?? 动态sql和batch插入哪个效率高?
  7. 插入后如何获取自动生成的主键值

    • <insert id="insertname" usegeneratedkeys="true" keyproperty="id"> insert into names (name) values (#{name}) </insert>
  8. 动态sql作用?执行原理?哪些动态sql

    1. 动态sql编写在xml中,根据入参不同生成不同的sql
    2. 执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。
    3. 9种动态sql标签 trim | where | set | foreach | if | choose | when | otherwise | bind
  9. 一对一查询
    主要是association标签
    两种方式,一种是一次查询,通过sql关联表查询;还有一种是两次单表查询
    不过两次查询这种有一定限制,毕竟是先单表查询的
    ??必须是两次单表查询?好像也不一定

    <!-- 一对一根据id查询个人信息:级联查询的第一种方法(嵌套查询,执行两个SQL语句)-->
    <resultMap type="com.po.Person" id="cardAndPerson1">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <!-- 一对一级联查询-->
        <association property="card" column="idcard_id" javaType="com.po.Idcard"
        select="com.dao.IdCardDao.selectCodeByld"/>
    </resultMap>
    <select id="selectPersonById1" parameterType="Integer" resultMap=
    "cardAndPerson1">
        select * from person where id=#{id}
    </select>
    <!--对一根据id查询个人信息:级联查询的第二种方法(嵌套结果,执行一个SQL语句)-->
    <resultMap type="com.po.Person" id="cardAndPerson2">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <!-- 一对一级联查询-->
        <association property="card" javaType="com.po.Idcard">
            <id property="id" column="idcard_id"/>
            <result property="code" column="code"/>
        </association>
    </resultMap>
  1. 一对多查询
    主要就是 collection 标签
    要求两表查询出来的字段不一样不?

  2. MyBatis 延迟加载实现原理
    Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。

  3. MyBatis 的一二级缓存
    一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
    二级缓存:与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
    一级缓存为Session级别缓存,默认打开;二级缓存为Mapper级别缓存(跨Session),默认关闭
    默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

  4. Spring 下 MyBatis 缓存失效
    一级缓存失效,因为 MyBatis 的连接被交给 Spring 管理了,每次事务结束都 close 了

  5. MyBatis 接口绑定
    就是将接口方法与SQL进行映射,调用方法即执行对应SQL。
    两种方法,一种注解,一种XML

  6. MyBatis 拦截器
    Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。编写插件:实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

参考

  1. 2022 最新MyBatis 面试题 https://www.cnblogs.com/d102601560/p/15758723.html
  2. Mybatis面试题(2021最新版)https://cloud.tencent.com/developer/article/1814879
  3. MyBatis一对一关联查询(级联查询)http://c.biancheng.net/view/4368.html
  4. MyBatis一对多关联查询 http://c.biancheng.net/mybatis/one-to-many.html
  5. mybatis中批量插入的两种方式(高效插入) https://zhuanlan.zhihu.com/p/35305211
  6. 坑已踩好,MyBatis 几种批量插入性能比较 https://jishuin.proginn.com/p/763bfbd670ad
  7. Mybatis 批量插入 https://www.cnblogs.com/edda/p/14026230.html
  8. MyBatis原理分析之六:RowBounds分页原理 https://blog.csdn.net/cb_lcl/article/details/81867772
  9. Mybatis四种分页方式 https://www.w3cschool.cn/mybatis/mybatis-ypsj3bpi.html
  10. mybatis中四种模糊查询的方式 https://blog.csdn.net/Adobe_java/article/details/118460709
posted @ 2022-04-06 01:03  YangDanMua  阅读(39)  评论(0编辑  收藏  举报