Mybatis常见知识点

 

我在个人简历上面没有写持久层框架,所以这方面在面试的过程问的也比较少,自己总结的也比较粗糙。问的最多的是第二点和第十点


一:工作流程

通过数据源创建一个数据库连接,将创建的数据库连接统一放到连接池进行管理,减少每次创建和断开数据库连接的开销。通过Sqlsession去操作数据库连接。

 

Mybatis常见知识点


二:#{…} 和${…} 的区别

sql 注入只对 sql 语句的编译过程有破坏作用,而 PreparedStatement 已经编译好了,执行阶段只是把输入串作为数据处理,而不再对 sql 语句进行解析,准备,因此也就避免了 sql 注入问题。

#{}是预编译处理,$ {}是字符串替换。mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。使用 #{} 可以有效的防止SQL注入,提高系统安全性


三:动态sql

If:经常用作非空判断和真假判断;

choose when otherwise:类似 switch case default;

Where:代替sql中的where 1=1,使sql语句正确

trim;用来去除特殊的字符

set:用于更新操作,只需要发送需要更新的字段,不用像Hibernate那样发送整个pojo

Foreach:针对数组和集合进行循环遍历(这是实现批量查询的关键)

Select * from table_name where id in

<foreach item=id index=index collection=list open=( separator=, close=)>

#{id}

</foreach>

当传入的是单参数且参数类型是数组或者list时,collection的值为array和list

当传入的多个参数,就需要将参数封装成map,collection的值是Map的键

当传入的是一个pojo时,collection的值为该类中需要进行遍历的数组或集合的属性名


四:mybatis的关联查询

所谓关联,就是在一个pojo中存在另外一个pojo。这两个pojo的关系可能是一对一(一个用户pojo唯一对应一个IdCard的pojo),一对多(一个用户pojo对应多个订单Order的pojo),多对多(一个订单Order的pojo对应多个商品Product的pojo,反之一个商品Producet的pojo也可以对应多个订单Order的pojo)。

实现方式有两种:

嵌套查询,通过select引入另外一个查询的sql:缺点可能导致较多关联sql被执行。

嵌套结果:只需要将所有要查询的字段写在一个从多表中进行查询的sql,一次执行。

一对一:association;一对多:collection;多对多:collection,需要借助一个中间表。


五:****注意事项

selectByExample 和selectByExampleWithBLOBs 两个方法的区别

1>两个方法的返回的resultMap不同

selectByExample  方法返回:BaseResultMap

selectByExampleWithBLOBs  方法返回:ResultMapWithBLOBs

ResultMapWithBLOBs定义时,继承了BaseResultMap,并且自己特殊的字段,该字段通常是longvarchar类型,

2>使用场景不同

若检索大字段时,则需要使用selectByExampleWithBLOBs ,一般情况则使用selectByExample 即可。


六:常见的持久层框架

概念:

jdbc是java连接数据库操作的原生接口

jpa是java持久化规范,是orm框架的标准,主流orm框架都实现了这个标准

spring data jpa是对jpa规范的再次抽象,底层还是用的实现jpa的hibernate技术

hibernate是一个标准的orm框架,实现了jpa

mybatis也是一个持久化框架,但不完全是一个orm框架,不是依照的jpa规范。

联系:

jdbc是比较底层的数据库操作方式,hibernate和mybatis都是在jdbc的基础上进行了封装。

hibernate是将数据库中的数据表映射为持久层的java对象,实现对数据表的完整性控制。hibernate的主要思想是面向对象,标准的orm。不建议自己写sql语句,如果确实有必要推荐hql代替。hibernate是全表映射,只需提供java bean和数据库表映射关系,

mybatis是将sql语句中的输入参数parameterMap和输出结果resultMap映射为java对象,放弃了对数据表的完整性控制,获得了更大的灵活性。mybatis拥抱sql,在sql语句方面有更大的灵活性,mybatis不是面向对象,不是标准的orm,更像是sql mapping框架。mybatis是半自动的,需要提供java bean,sql语句和数据库表的映射关系。


七:dbcp 和 c3p0 的区别

连接池的配置参数:

driverClassName:com.mysql.jdbc.Driver,

Url:jdbc:mysql://localhost:3306/taotao?characterEncoding=utf-8

Hostname:root

Password:root

dbcp 没有自动的去回收空闲连接的功能 c3p0 有自动回收空闲连接功能 C3P0提供最大空闲时间,DBCP提供最大连接数。前者当连接超过最大空闲连接时间时当前连接就会被断掉。DBCP当连接数超过最大连接数时,所有连接都会被断开。所以dbcp会出现丢连接的情况。


八:xml文件和对应dao的关系

通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?

 Dao接口,就是人们常说的 Mapper接口,接口的全限名,就是映射文件中的 namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement。Dao 接 口的工作原理是JDK动态代理,Mybatis 运行时会使用JDK 动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql 执行结果返回。Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。


九:常见问题

1:当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致

Mybatis常见知识点

 

第2种: 通过来映射字段名和实体类属性名的一一对应的关系

Mybatis常见知识点


十:缓存

Mybatis的一级缓存是SqlSession级别。第一次执行select时候会发现sqlsession缓存没有记录,会去数据库查找,然后把结果保存到缓存,第二次同等条件查询下,就会从缓存中查找到结果。另外为了避免脏读,每次执行更新新增删除时候会清空当前sqlsession缓存。

怎么判断某两次查询是完全相同的查询?

mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。

2.1 传入的statementId

2.2 查询时要求的结果集中的结果范围

2.3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )

2.4 传递给java.sql.Statement要设置的参数值

二级缓存是namespace级别的。同一个namespace下的搜寻语句共享一个二级缓存。如果开启了二级缓存,则先从二级缓存中查找,查找不到则委托为SimpleExecutor查找,而它则会先从一级缓存中查找,查找不到则从数据库查找。

一、创建一个POJO Bean并序列化

  由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化

 二、在映射文件中开启二级缓存

    <!--

        eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。

        (1) LRU,最近最少使用的,一处最长时间不用的对象

        (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们

        (3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象

        (4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU, 移除最长时间不用的对形象

        flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当 SQL被执行的时候才会去刷新缓存。

        size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。 这里配置的是1024个对象

        readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有办法修改缓存,默认值是false,不允许我们修改

    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

三、在 mybatis-config.xml中开启二级缓存

    <settings>

        <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->

        <setting name="cacheEnabled" value="true" />

        .....

    </settings>