Mybatis学习笔记
结果映射(resultMap)
-
association
– 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是
resultMap
元素,或是对其它结果映射的引用
- 嵌套结果映射 – 关联可以是
-
collection
– 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是
resultMap
元素,或是对其它结果映射的引用
- 嵌套结果映射 – 集合可以是
SQL:
CREATE table `teacher`(
`id` int(10) not null ,
`name` varchar(30) default null,
primary key (`id`)
)engine=INNODB default charset =utf8;
insert into teacher() values (1,"贾老板");
create table `student`(
`id` int(10) not null ,
`name` varchar(30) default null,
`tid` int(10) default null,
primary key (id),
key `fktid` (`tid`),
constraint `fktid` foreign key (`tid`) references `teacher`(`id`)
)engine = innodb default charset = utf8;
insert into `student` values (1,'小白',1),(2,'小于',1),(3,'小红',1),(4,'小蓝',1),(5,'小黑',1),(6,'小花',1);
多对一的形式
测试环境搭建
-
导入lombok
-
新建实体类Teacher、Student
-
建立Mapper接口
-
建立Mapper.xml文件
按照子查询
<select id="getStudent" resultMap="Student_tea"> select * from mybatis.student </select> <resultMap id="Student_tea" type="Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!--复杂的属性需要单独处理 对象:association 集合:collection --> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from mybatis.teacher where id=#{id} </select>
按照结果查询
<select id="getStudent2" resultMap="Student_tea2"> select s.id sid, s.name sname, t.name tname from student s,teacher t where s.tid = t.id </select> <resultMap id="Student_tea2" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap>
-
在核心被配置文件注册我们的Mapper接口或者文件
-
测试
一对多的形式
测试环境搭建**
-
导入lombok
-
新建实体类Teacher、Student
-
建立Mapper接口
-
建立Mapper.xml文件
按照结果查询
<select id="getTeacherById" resultMap="TeacherStudent"> select s.id sid, s.name sname, t.name tname, t.id tid from mybatis.student s, mybatis.teacher t where s.tid = t.id and tid = #{tid} </select> <resultMap id="TeacherStudent" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <!--复杂的属性,需要单独处理 对象:associate 集合:collection javaType="" 指定属性的类型 集合中泛型信息,我们使用ofType获取 --> <collection property="students" ofType="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap>
-
在核心被配置文件注册我们的Mapper接口或者文件
-
测试
回顾Mysql多对一进行查询
- 子查询
- 联表查询
总结
- 关联 - associate【多对一】
- 集合 - collection 【一对多】
- JavaType & ofType
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
https://mybatis.org/mybatis-3/zh/dynamic-sql.html
If
<select id = "queryBlog" parameterType="map" resultType="blog">
SELECT * FROM User WHERE 1=1
<if test="title != null">
and title=#{title}
</if>
</select>
choose,when,otherwise
它有点像 Java 中的 switch 语句。when
和otherwise
是choose中的标签
choose
类似于switch
when
类似于case
otherwise
类似于default
trim,where,set
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<where></where> 注意where中的第一个sql语句不用添加and,其他的需要在开头添加and
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
SQL片段
有时候,可能将一些功能的部分抽取出来,方便复用
-
使用SQL标签抽取公共部分
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> </sql>
-
需要使用的地方使用
include
标签<select id ="queryBlog" parametertype="map" resultType="blog"> <where> <include refid="if-title-author"/> </where> </select>
注意事项:
- 最好基于单表来定义SQL片段
- 不要存在
Where
标签
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
至此,我们已经完成了与 XML 配置及映射文件相关的讨论。下一章将详细探讨 Java API,以便你能充分利用已经创建的映射配置。
Mybatis缓存
简介
- 什么是缓存[Cache]?
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题
- 为什么使用缓存?
- 减少和数据库的交互次数,减少系统开销,提高系统效率
- 什么样的数据能使用缓存?
- 经常查询且不经常改变的数据【可以使用缓存】
MyBatis缓存
- MyBatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存。缓存可以极大的提升查询效率
- MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置,它是基于namespace级别的缓存
- 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存
一级缓存
也成为本地缓存
- 与数据库同一次会话期间查询到的数据会放在本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前的一级缓存中
- 如果当前会话关闭了,这个会话对应的一级缓存就没了,但是想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
- 新的会话查询信息,就可以从二级缓存中获取内容
- 不同的mapper查出的数据会放在自己对应的缓存(map)中
步骤:
-
开启全局缓存
<!--显示开启全局缓存--> <setting name="cacheEnabled" value="true">
-
在要使用二级缓存的Mapper中开启
<!--在当前Mapper.xml中使用二级缓存--> <cache/>
也可以自定义参数
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
-
测试
-
问题:我们需要将实体类序列化,否则将会报错
Caused by: java.io.NotSerializableException:com.xdu.pojo.User
-
小结:
- 只要开启二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在一级缓存中
- 只有会话提交,或者关闭的时候,才会提交到二级缓存中
缓存顺序:
-
先走二级缓存(Mapepr)
2. 如果没有二级缓存,再走一级缓存(SqlSession) 3. 如果没有一级缓存,再走数据库