1. mybatis缓存机制
介绍 : MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在 session 里面,默认就有,二级缓 存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现 Serializable 序列化 接口(可用来保存对象的状态),可在它的映射文件中配置 ** ** 标签即可
一级缓存 : 在一次数据库会话里 用户发起查询时 查询结果会缓存到mybatis的sql session里 该区域结果是一个map 当我们再次查询相同的数据 会直接到该区域查询返回结果 如果没有 则查询数据库
问题 : 如何两次查询一个数据时,中间对这个数据进行了更新操作 怎么办 ??? 在mybatis里在执行更新操作后 会把一级缓存清空
手动清理缓存 使用SqlSession对象调用clearCache()方法 SqlSession.clearCache();
二级缓存 : 二级缓存指的是 mybatis中SqlSessionFactory对象的缓存 ,由同一个SqlSessionFactory对象 创建的SqlSession共享缓存
注意 : mybatis的二级缓存SqlSessionFactory中存放的是是数据 而不是对象
2. Mybatis 是如何进行分页的?分页插件的原理是什么?
Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用 Mybatis 的分页插件
**RowBounds ** : 不需要在 sql 语句中写 limit,即可完成分页功能。但是由于它是在 sql 查询出所有结果的基础上截取数据的,所以在数据量大的sql中并不适用,它更适合在返回数据结果较少的查询中使用
分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法内拦 截待执行的 sql,然后重写 sql。
select * from student
select t
.* from (
select * from student)t
limit 0,
10
3.Mybatis 动态 sql 是做什么的?都有哪些动态 sql?简述一下动态 sql 的执行原理?
Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑 判断和动态拼接 sql 的功能trim / where / set / foreach / if / choose when otherwise / bind。通过ognl表达式获取sql参数值 根据参数值动态拼接sql语句
3. #{}和${}的区别是什么?
**#{}是预编译处理,${}**是字符串替换。
Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
PreparedStatement 会把用户的非法传参使用 \ 来标识 以达到防止sql注入问题
Mybatis 在处理
时
,
就
是
把
{}时,就是把
时,就是把{}替换成变量的值。(调用Statement对象)
4.为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象 时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或 关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具
5.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()方法的调用。这就是延迟加载的基本原理。
6.简述 Mybatis 的 Xml 映射文件和 Mybatis 内部数据结构之间的映射关系?
Mybatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中,标签会被解析为 ParameterMap 对象,其每个子元素会 被解析为 ParameterMapping 对象。标签会被解析为 ResultMap 对象,其每个子 元素会被解析为 ResultMapping 对象。每一个、、、标签 均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象。
7.什么是 MyBatis 的接口绑定,有什么好处?
即在mybatis里自定义接口 该接口方法与xml文件的sql语句绑定 我们直接调用接口方法即可实现与数据库交互 比原生是sqlSession方法更加灵活高效
8.接口绑定有几种实现方式,分别是怎么实现的?
注解 : 直接在接口方法上统计@select @delete @update @insert注解 并在注解里写入sql语句实现xml : 指定映射文件 (namespace后添加接口类的全路径实现接口映射) 实现xml自定义sql语句
9.MyBatis 实现一对一有几种方式?具体怎么操作的?
联表查询 : 通过在 resultMap 里面配置 association 属性 实现一对一嵌套查询 : 先查一个表,根据这个表里面的结果的外键 id,去再另外一个表里面查询数据,也是通过 association 配置,但另外一个表的 查询通过 select 属性配置
10.Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
使用 resultMap 标签进行逐个映射 如果使用resulttype标签 需要数据库字段和实体类字段一致使用sql别名进行属性映射
11.Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?
sql include 编写可共用的sql语句 使用include标签引入**resultMap ** : 建立 SQL 查询结果字段与实体属性的映射关系信息parameterMap : 一般使用parameterType 即可 用于接受参数selectKey : 为不支持主键自增长的表生成自增长主键动态标签
if : 成立则执行,不成立则不执行choose (when, otherwise) : 类似于java的switch() case语句trim : 截断 添加
prefix 在前面添加内容suffix 在后面添加内容suffixOverrides="," : 去掉最后一个 “,”prefixoverride="," : 去掉第一个"," foreach : 遍历数组 集合where : sql判断
当编写where标签时,如果内容中第一个是and去掉第一个and如果 中有内容会生成where关键字,如果没有内容不生成where关键字 **set ** : sql修改
去掉最后一个逗号如果里面有内容就会生成set关键字,没有就不生成 bind : 模糊查询
给参数重新赋值
12.当实体类中的属性名和表中的字段名不一样,如何将查询的结果封装到指定 pojo?
使用sql别名功能匹配使用resultMap标签匹配
13.模糊查询 like 语句该怎么写
‘%${question}%’ 不推荐 存在sql注入风险CONCAT(’%’,#{question},’%’) 推荐NAME like ‘%’|| #{name} || ‘%’使用bind
<bind name
="pattern" value
="'%' + _parameter.username + '%'" />
select
* from person where username LIKE #
{pattern
}
14.通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, Dao 的工作原理,是否可以重载?
不能重载,因为通过 Dao 寻找 Xml 对应的 sql 的时候全限名+方法名的保存和寻找策略。接口工作原理为 jdk 动态代理原理,运行时会为 dao 生成 proxy,代理对象会拦截接口方法,去执行对应的 sql 返回数据。
15.Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问,B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?
虽然 Mybatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可以定义在任何地方,Mybatis 都可以正确识别。原理是,Mybatis 解析 A 标签,发现 A 标签引用了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,Mybatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,Mybatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时,B 标签已经存在,A 标签也就可以正常解析完成了。
16.Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。原因就是 namespace+id 是作为 Map<String, MappedStatement>的 key 使用的,如果没有namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。
17.Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?
Mybatis 有三种基本的 Executor 执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
1)SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。2)ReuseExecutor:执行 update 或 select,以 sql 作为key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map3)BatchExecutor:执行update(没有select,JDBC批处理不支持select) 将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
18.Mybatis 中如何指定使用哪一种 Executor 执行器?
在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
19.Mybatis 执行批量插入,能返回数据库主键列表吗?
可以 使用 useGenerateKeys和keyProperty返回主键列表
20.在 mapper 中如何传递多个参数?
封装一个实体类 或者直接传多个参数 使用 #{}来获取如果传参接收不到可以使用 @param 注解
21.resultType resultMap 的区别?
类的名字和数据库相同时,可以直接设置 resultType 进行自动映射如果不相同则定义resultMap实现字段和实体类属性名称的匹配
22.使用 MyBatis 的 mapper 接口调用时有哪些要求?
Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同Mapper 接口方法的返回值类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径在使用foreach标签时如果有多个入参 则collection属性值为对应参数名称