1. 什么是Mybatis
Mybatis是一款优秀持久层的框架。内部封装了JDBC,开发时只需要关注SQL语句的,不需要花时间精力去加载驱动、创建连接、创建statement、执行sql、处理结果集等过程。MyBatis可以使用xml或者注解来配置和映射原生信息,将java中的pojo对象映射成数据库中的记录。
2.MyBatis的优缺点
- 优点
- 基于sql语句编写代码,与JDBC相比,减少了代码量,消除了JDBC大量的冗余代码
- MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持,数据库兼容性很好
- 能够与Spring继承
- 提供映射标签,可以支持复杂的映射关系处理
- 缺点
- sql语句编写工作量较大
3. #{}和${}的区别
#{}:是预编译处理,能防止sql注入
${}:是字符串替换,一般使用是列名表名,不同排序规则
4.处理实体类中属性名和表字段不一致问题
- 通过sql查询语言定义字段的别名,让字段的别名和实体类的属性名相同
- 通过结果集映射将实体类的属性和数据表的字段一一对应
5.MyBatis如何分页的
MyBatis是使用RowBounds对象进行分页,它是正针对ResultSet结果集执行的所有结果进行分页,是逻辑分页。pageHelper分页插件的基本原理是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截等待执行的sql,然后重写sql,根据结果,添加对应的物理分页参数limit x y。
6.MyBatis一对一、一对多处理
一对一(多对一)
使用association嵌套查询(association使用一个复杂类型的关联将许多结果集包装成一种类型)
<select id="getAllStudent" resultMap="students">
select * from student
</select>
<resultMap id="students" type="com.study.pojo.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association property="teacher" javaType="com.study.pojo.Teacher" column="tid" select="teachers" ></association>
</resultMap>
<select id="teachers" resultType="com.study.pojo.Teacher">
select * from teacher where id=#{id}
</select>
<!--其中association的column是传递的参数,就是给嵌套的子查询传递参数。
也可以使用column="{prop1=col1,prop2=col2}"传递多个参数-->
使用association结果嵌套
<select id="getAllStudent2" resultMap="student2">
select s.id id,s.name name ,t.id tid,t.name tname from student s,teacher t where s.tid = t.id
</select>
<resultMap id="student2" type="com.study.pojo.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association property="teacher" javaType="com.study.pojo.Teacher" resultMap="teacher" />
</resultMap>
<resultMap id="teacher" type="com.study.pojo.Teacher">
<result column="tid" property="id"/>
<result column="tname" property="name"/>
</resultMap>
一对多
使用collection嵌套查询(一个复杂类型的集合)
<select id="getTeacherStudent" resultMap="teacher1">
select * from teacher
</select>
<resultMap id="teacher1" type="com.study.pojo.Teacher">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="students" column="id" ofType="com.study.pojo.Student" select="students"/>
</resultMap>
<select id="students" resultType="com.study.pojo.Student">
select * from student where tid=#{id}
</select>
使用collection处理结果集
<select id="getTeacherStudent2" resultMap="teacher2">
select t.id id,t.name name,s.id sid,s.name sname,s.tid tid from teacher t,student s where t.id=s.tid
</select>
<resultMap id="teacher2" type="com.study.pojo.Teacher">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="students" ofType="com.study.pojo.Student">
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
7.MyBatis延迟加载
MyBatis默认关闭延迟加载,可以在Mybatis配置文件中配置是否启用延迟加载lazyLoadingEnabled=true|false。
原理是通过代理工具(CGLIB3.5.10已弃用|JAVASSIST)代理目标对象的,当调用方法时,进入拦截器,就会通过拦截器控制invoke方法的执行,实现association或者collection的嵌套查询值处理。
8.MyBatis缓存机制
一级缓存
Mybatis默认开启一级缓存。在一次sql数据库会话中,执行了多次查询条件完全相同的sql,MyBatis提供了一种一级缓存的方案优化,如果是相同的sql语句,会优先名字一级缓存,避免直接对数据库的查询,提高性能。
每个SqlSession中有意Executor引用指向CachingExecutor对象,该对象中有一个Executor引用指向SimpleExecutor对象,在SimpleExecutor对象中有一个引用指向PerpetualCache localCache,这个对象中有属性id固定为LocalCache,还有一个cache名的HashMap集合,map集合的key为方法的一些信息,value为方法查到的结果。
Mybatis一级缓存和生命周期和SqlSession一致。
MyBatis一级缓存设计简单,缓存的集合是一个new HashMap<Object,Object>集合,其中key为sql查询的信息,value为查询出来的结果。
MyBatis的一级缓存存在SqlSession下的CachingExecutor下SimpleExecutor下PerpetualCache中的cacheHashMap集合。
二级缓存
二级缓存需要手动开启和配置,他是基于 cache 标签所在的映射文件中的语句(基于namespace级别的缓存)。要使用二级缓存,被缓存的对象要实现序列化接口。
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
查看Mybatis源码得知:每次查询都需要通过CachingExecutor先查看二级缓存是否开启,如果没有开启再去查一级缓存有没有数据,最终才连数据库查询。