Mybatis学习笔记03

1.一对多和多对一处理

1.1 多对一的处理

多对一的理解:

  • 多个学生对应一个老师
  • 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师
  1. 数据库设计:
  1. CREATE TABLE teacher(
  2. -> id INT(10) NOT NULL,
  3. -> name VARCHAR(30) DEFAULT NULL,
  4. -> PRIMARY KEY(id)
  5. -> )ENGINE=INNODB DEFAULT CHARSET=utf8;
  6. insert into teacher(id,name) values(1,"张老师");
  7. CREATE TABLE student(
  8. -> id INT(10) NOT NULL,
  9. -> name VARCHAR(30) DEFAULT NULL,
  10. -> tid INT(10) DEFAULT NULL,
  11. -> PRIMARY KEY(id),
  12. -> KEY fktid(tid),
  13. -> CONSTRAINT fktid FOREIGN KEY(tid) REFERENCES teacher (id)
  14. -> )ENGINE=INNODB DEFAULT CHARSET=UTF8;
  15. INSERT INTO student (id,name,tid) VALUES(1,"小明",1);
  16. INSERT INTO student (id,name,tid) VALUES(2,"小王",1),(3,"小李",1),(4,"小刘",1),(5,"小陈",1);

Mybatis学习笔记03 - 图1Mybatis学习笔记03 - 图2

  1. 搭建测试环境

  2. IDEA安装Lombok插件

  3. 引入Maven依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.projectlombok</groupId>
  4. <artifactId>lombok</artifactId>
  5. <version>1.18.10</version>
  6. </dependency>
  7. </dependencies>
  1. 在代码中增加注解
  1. @Data
  2. public class Student {
  3. private int id;
  4. private String name;
  5. //学生需要关联一个老师
  6. private Teacher teacher;
  7. }
  1. @Data
  2. public class Teacher {
  3. private int id;
  4. private String name;
  5. }
  1. 编写实体类对应的Mapper接口
  1. public interface TeacherMapper {
  2. @Select("select * from teacher where id=#{tid}")
  3. Teacher getTeacher(@Param("tid") int id);
  4. }
  1. public interface StudentMapper {
  2. }
  1. 编写Mapper接口对应的mapper.xml对应文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.TeacherMapper">
  6. </mapper>
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.StudentMapper">
  6. </mapper>
  1. 注册mapper
  1. <mappers>
  2. <mapper resource="StudentMapper.xml"/>
  3. <mapper resource="TeacherMapper.xml"/>
  4. </mappers>
  1. 测试
  1. public class MyTest {
  2. public static void main(String[] args) {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
  5. Teacher teacher = mapper.getTeacher(1);
  6. System.out.println(teacher);
  7. sqlSession.close();
  8. }
  9. }

Mybatis学习笔记03 - 图3

  1. 按查询嵌套处理和按结果嵌套处理

  2. 给StudentMapper接口增加方法

  1. //查询所有的学生信息以及老师信息
  2. public List<Student> getStudents();
  3. public List<Student> getStudents2();
  1. 编写对应的mapper文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.StudentMapper">
  6. <select id="getStudents" resultMap="StudentTeacher">
  7. select * from student
  8. </select>
  9. <resultMap id="StudentTeacher" type="student">
  10. <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
  11. </resultMap>
  12. <select id="getTeacher" resultType="teacher">
  13. select * from teacher where id = #{id}
  14. </select>
  15. <!-- ================================================-->
  16. <select id="getStudents2" resultMap="StudentTeacher2">
  17. select s.id sid, s.name sname, t.name tname from student s,teacher t where s.tid=t.id
  18. </select>
  19. <resultMap id="StudentTeacher2" type="Student">
  20. <id property="id" column="sid"/>
  21. <result property="name" column="sname"/>
  22. <association property="teacher" javaType="Teacher">
  23. <result property="name" column="tname"/>
  24. </association>
  25. </resultMap>
  26. </mapper>
  1. 编写完毕后去Mybatis配置文件中注册mapper
  1. <!-- 注册mapper-->
  2. <mappers>
  3. <mapper resource="StudentMapper.xml"/>
  4. <mapper resource="TeacherMapper.xml"/>
  5. </mappers>
  1. 分别测试
  1. @Test
  2. public void test1(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
  5. List<Student> students=mapper.getStudents();
  6. for (Student student : students) {
  7. System.out.println("学生名:"+student.getName()+"\t老师:"+student.getTeacher().getName());
  8. }
  9. sqlSession.close();
  10. }
  11. @Test
  12. public void test2(){
  13. SqlSession sqlSession = MybatisUtils.getSqlSession();
  14. StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
  15. List<Student> students=mapper.getStudents2();
  16. for (Student student : students) {
  17. System.out.println("学生名:"+student.getName()+"\t老师:"+student.getTeacher().getName());
  18. }
  19. sqlSession.close();
  20. }
  1. 结果

Mybatis学习笔记03 - 图4

总结:

  • 按照查询进行嵌套处理就像sql中的子查询
  • 按照结果表进行嵌套处理就像sql中的联表查询

1.2 一对多处理

一对多的理解:

  • 一个老师拥有多个学生
  • 如果对于老师这边,就是一个一对多的现象,即从一个老师下面拥有一群学生
  1. 实体类编写
  1. @Data
  2. public class Student {
  3. private int id;
  4. private String name;
  5. private int tid;
  6. }
  1. @Data
  2. public class Teacher {
  3. private int id;
  4. private String name;
  5. //一个老师对应多个学生
  6. private List<Student> students;
  7. }
  1. 按结果嵌套处理和按查询嵌套处理表

    首先TeacherMapper接口编写方法

  1. public interface TeacherMapper {
  2. //获取指定老师及老师下的所有学生
  3. public Teacher getTeacher(int id);
  4. public Teacher getTeacher2(int id);
  5. }
  1. 然后编写接口对应的Mapper配置文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.TeacherMapper">
  6. <select id="getTeacher" resultMap="TeacherStudent">
  7. select s.id sid, s.name sname,t.name tname,t.id tid from student s,teacher t where s.tid=t.id and t.id=#{id}
  8. </select>
  9. <resultMap id="TeacherStudent" type="Teacher">
  10. <result property="name" column="tname"/>
  11. <collection property="students" ofType="Student">
  12. <result property="id" column="sid"/>
  13. <result property="name" column="sname"/>
  14. <result property="tid" column="tid"/>
  15. </collection>
  16. </resultMap>
  17. <!-- =====================================================-->
  18. <select id="getTeacher2" resultMap="TeacherStudent2">
  19. select * from teacher where id=#{id}
  20. </select>
  21. <resultMap id="TeacherStudent2" type="Teacher">
  22. <!-- column是一对多的外键,写的是一的主键的列名-->
  23. <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
  24. </resultMap>
  25. <select id="getStudentByTeacherId" resultType="Student">
  26. select * from student where tid=#{id}
  27. </select>
  28. </mapper>

最后将Mapper文件注册到mybatis-config文件中

  1. <!-- 注册mapper-->
  2. <mappers>
  3. <mapper resource="StudentMapper.xml"/>
  4. <mapper resource="TeacherMapper.xml"/>
  5. </mappers>
  1. 分别进行测试
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. TeacherMapper mapper= sqlSession.getMapper(TeacherMapper.class);
  5. Teacher teacher=mapper.getTeacher(1);
  6. System.out.println(teacher.getName());
  7. System.out.println(teacher.getStudents());
  8. }
  9. @Test
  10. public void test2(){
  11. SqlSession sqlSession = MybatisUtils.getSqlSession();
  12. TeacherMapper mapper= sqlSession.getMapper(TeacherMapper.class);
  13. Teacher teacher=mapper.getTeacher2(1);
  14. System.out.println(teacher.getName());
  15. System.out.println(teacher.getStudents());
  16. }
  1. 结果

Mybatis学习笔记03 - 图5

1.3 小结

  1. 关联-association
  2. 集合-collection
  3. association用于一对一和多对一,而collection是用于一对多的关系
  4. JavaType和ofType都是用来指定对象类型的

    • JavaType是用来指定pojo中属性的类型
    • ofType指定的是映射到list集合属性中pojo的类型

注意说明:

  • 保证sql的可读性,尽量通俗易懂
  • 根据实际要求,尽量编写性能更高的sql语句
  • 注意属性名与字段不一致的问题
  • 注意一对多和多对一中:字段和属性对应的问题
  • 尽量使用Log4j,通过日志来查看自己的错误

2.动态SQL

2.1 动态SQL环境搭建

什么是动态SQL?

动态SQL指的是根据不同的查询条件,生成不同的sql语句

我们之前写的sql语句都比较简单,如果有比较复杂的业务,我们需要写复杂的sql语句,往往需要拼接,而拼接sql,稍微不注意,由于引号,空格等缺失可能都会导致错误,那么怎么解决这个问题呢?这时就需要使用Mybatis动态sql,通过if,choose,when,otherwise,trim,where,set,foreach等标签可以组成非常灵活的sql语句,从而在提高sql语句的准确性的同时,也大大提高了开发人员的效率

  1. 搭建环境:

  2. 新建一个数据库表:blog

字段:id ,title,author,create_time,views

  1. CREATE TABLE blog (
  2. id VARCHAR(50) NOT NULL COMMENT '博客id',
  3. title VARCHAR(100) NOT NULL COMMENT '博客标题',
  4. author VARCHAR(30) NOT NULL COMMENT '博客作者',
  5. create_time datetime NOT NULL COMMENT '创建时间',
  6. views INT(30) NOT NULL COMMENT '浏览量'
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 实体类编写(注意set方法作用)
  1. @Data
  2. public class Blog {
  3. private String id;
  4. private String title;
  5. private String author;
  6. private Date createTime;
  7. private int views;
  8. }
  1. IDutil工具类(用来随机获得id)
  1. public class Idutils {
  2. public static String getId(){
  3. return UUID.randomUUID().toString().replaceAll("-","");
  4. }
  5. @Test
  6. public void test(){
  7. System.out.println(Idutils.getId());
  8. }
  9. }
  1. 编写mapper接口及xml文件
  1. public interface BlogMapper {
  2. //插入数据
  3. int addBlog(Blog blog);
  4. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.BlogMapper">
  6. <insert id="addBlog" parameterType="blog">
  7. insert into mybatis.blog(id, title, author, create_time, views)
  8. VALUES (#{id},#{title},#{author},#{createTime},#{views})
  9. </insert>
  10. </mapper>
  1. mybatis核心配置文件,配置下峰线驼峰自动转换
  1. <settings>
  2. <setting name="mapUnderscoreToCamelCase" value="true"/>
  3. <setting name="logImpl" value="STDOUT_LOGGING"/>
  4. </settings>
  1. 初始化博客方法
  1. @Test
  2. public void addInitBlog(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);
  5. Blog blog=new Blog();
  6. blog.setId(Idutils.getId());
  7. blog.setTitle("mybatis如此简单");
  8. blog.setAuthor("jcsune");
  9. blog.setCreateTime(new Date());
  10. blog.setViews(9999);
  11. mapper.addBlog(blog);
  12. blog.setId(Idutils.getId());
  13. blog.setTitle("Java如此简单");
  14. mapper.addBlog(blog);
  15. blog.setId(Idutils.getId());
  16. blog.setTitle("Spring如此简单");
  17. mapper.addBlog(blog);
  18. blog.setId(Idutils.getId());
  19. blog.setTitle("微服务如此简单");
  20. mapper.addBlog(blog);
  21. sqlSession.close();
  22. }
  1. 查看结果

Mybatis学习笔记03 - 图6

2.2 动态SQL之IF语句

需求:根据作者名字和博客名字来查询博客,如果作者名字为空,那么只根据博客名字查询,反之则根据作者名字查询

  1. 编写接口类
  1. //IF查询
  2. List<Blog> queryBlogIf(Map map);
  1. 编写sql语句
  1. <select id="queryBlogIf" parameterType="map" resultType="blog">
  2. select * from blog where
  3. <if test="title != null">
  4. title=#{title}
  5. </if>
  6. <if test="author != null">
  7. and author= #{author}
  8. </if>
  9. </select>
  1. 测试
  1. @Test
  2. public void testQueryBlogIf(){
  3. SqlSession session = MybatisUtils.getSqlSession();
  4. BlogMapper mapper = session.getMapper(BlogMapper.class);
  5. HashMap<String, String> map = new HashMap<String, String>();
  6. map.put("title","mybatis如此简单");
  7. map.put("author","jcsune");
  8. List<Blog> blogs = mapper.queryBlogIf(map);
  9. System.out.println(blogs);
  10. session.close();
  11. }

2.3 动态SQL常用标签

Where

修改上节的SQL语句:

  1. <select id="queryBlogIf" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <if test="title != null">
  5. title=#{title}
  6. </if>
  7. <if test="author != null">
  8. and author= #{author}
  9. </if>
  10. </where>
  11. </select>

这个where标签会知道如果它包含的标签中有返回值的话,它就插入一个“where”,此外如果标签返回的内容是以“and”或者“or”开头的,则它会剔除掉

Set

同理,上面的对于查询SQL语句包含where关键字,如果在进行更新操作的时候,含有set关键词,我们怎么处理呢

  1. 编写接口方法
  1. int updateBlog(Map map);
  1. SQL配置文件
  1. <update id="updateBlog" parameterType="map">
  2. update mybatis.blog
  3. <set>
  4. <if test="title!=null">
  5. title=#{title},
  6. </if>
  7. <if test="author!=null">
  8. author=#{author}
  9. </if>
  10. </set>
  11. where id=#{id}
  12. </update>
  1. 测试
  1. @Test
  2. public void testUpdateBlog(){
  3. SqlSession session = MybatisUtils.getSqlSession();
  4. BlogMapper mapper = session.getMapper(BlogMapper.class);
  5. HashMap<String, String> map = new HashMap<String, String>();
  6. map.put("title","微服务如此简单2");
  7. map.put("author","jcsune");
  8. map.put("id","228916648b4f454885962b2d9165fec8");
  9. mapper.updateBlog(map);
  10. session.close();
  11. }
  1. 结果

Mybatis学习笔记03 - 图7

Choose

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用Choose标签可以解决此类问题,类似于java的switch语句

  1. 编写接口方法
  1. List<Blog> queryBlogChoose(Map map);
  1. sql 配置文件
  1. <select id="queryBlogChoose" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <choose>
  5. <when test="title!=null">
  6. title=#{title}
  7. </when>
  8. <when test="author!=null">
  9. and author=#{author}
  10. </when>
  11. <otherwise>
  12. and views=#{views}
  13. </otherwise>
  14. </choose>
  15. </where>
  16. </select>
  17. </mapper>
  1. 测试
  1. @Test
  2. public void testQueryBlogChoose(){
  3. SqlSession session = MybatisUtils.getSqlSession();
  4. BlogMapper mapper = session.getMapper(BlogMapper.class);
  5. HashMap<String, String> map = new HashMap<String, String>();
  6. map.put("title","mybatis如此简单");
  7. map.put("author","jcsune");
  8. map.put("views","9999");
  9. List<Blog> blogs = mapper.queryBlogChoose(map);
  10. System.out.println(blogs);
  11. session.close();
  12. }

2.4 动态SQL之Foreach

SQL片段

有时候可能某个sql语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用

提取SQL片段:

  1. <sql id="if-title-author">
  2. <if test="title!=null">
  3. title=#{title}
  4. </if>
  5. <if test="author!=null">
  6. and author=#{author}
  7. </if>
  8. </sql>

引用SQL片段:

  1. <select id="queryBlogIf2" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. /* 引用sql片段,如果refid指定的不在本文件中,那么需要在前面加上namespace*/
  5. <include refid="if-title-author"> </include>
  6. </where>
  7. </select>

注意:

  • 最好基于单表来定义sql片段,提高片段的可重用性
  • 在sql片段中不要包含where

Foreach:

将数据库中前三个数据的id修改为1,2,3;

需求:我们需要查询blog表中id分别为1,2,3,的博客信息

  1. 编写接口
  1. List<Blog> queryBlogForeach(Map map);
  1. 编写SQL语句
  1. <select id="queryBlogForeach" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <!--
  5. collection:指定输入对象中的集合属性
  6. item:每次遍历生成的对象
  7. open:开始遍历时的拼接字符串
  8. close:结束时拼接的字符串
  9. separator:遍历对象之间需要拼接的字符串
  10. select * from blog where 1=1 and (id=1 or id=2 or id=3)
  11. -->
  12. <foreach collection="ids" item="id" open="(" close=")" separator="or">
  13. id=#{id}
  14. </foreach>
  15. </where>
  16. </select>
  1. 测试
  1. @Test
  2. public void testQueryBlogForeach(){
  3. SqlSession sqlSession=MybatisUtils.getSqlSession();
  4. BlogMapper mapper=sqlSession.getMapper(BlogMapper.class);
  5. HashMap map=new HashMap();
  6. List<Integer> ids=new ArrayList<Integer>();
  7. ids.add(1);
  8. ids.add(2);
  9. ids.add(3);
  10. map.put("ids",ids);
  11. List<Blog> blogs=mapper.queryBlogForeach(map);
  12. System.out.println(blogs);
  13. sqlSession.close();
  14. }
  1. 结果:

Mybatis学习笔记03 - 图8

总结:

其实动态sql语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的sql语句出来,然后再通过mybatis动态sql对照着改,防止出错,多在实践中使用才是熟练掌握它的技巧

3. 缓存

3.1 缓存简介

  1. 简介

什么是缓存?

  • 存在内存中的临时数据
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题

为什么使用缓存?

  • 减少与数据库的交互次数,减少系统开销,提高系统效率

什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据
  1. mybatis缓存
  • Mybatis包含一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存,缓存可以极大的提升查询效率
  • Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存

    • 默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存
    • 为了提高扩展性,Mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来定义二级缓存

3.2 一级缓存

一级缓存也叫本地缓存:

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试:

  1. 在mybatis中加入日志,方便测试结果
  2. 编写接口方法
  1. public interface UserMapper {
  2. //根据id查询用户
  3. User queryUserById(@Param("id") int id);
  4. }
  1. 接口对应的mapper文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.jcsune.dao.UserMapper">
  6. <select id="queryUserById" resultType="user">
  7. select * from user where id=#{id}
  8. </select>
  9. </mapper>
  1. 测试
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. User user =mapper.queryUserById(1);
  6. System.out.println(user);
  7. System.out.println("============================");
  8. User user2=mapper.queryUserById(1);
  9. System.out.println(user2);
  10. System.out.println(user==user2);
  11. sqlSession.close();
  12. }
  1. 结果分析

Mybatis学习笔记03 - 图9

一级缓存失效的四种情况

一级缓存是Sqlsession级别的缓存,是一直开启的,我们关闭不了它

一级缓存失效的情况:没有使用到当前的一级缓存,效果就是还需要再向数据库中发起一次查询要求

  1. sqlsession不同
  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. SqlSession session2 = MybatisUtils.getSession();
  5. UserMapper mapper = session.getMapper(UserMapper.class);
  6. UserMapper mapper2 = session2.getMapper(UserMapper.class);
  7. User user = mapper.queryUserById(1);
  8. System.out.println(user);
  9. User user2 = mapper2.queryUserById(1);
  10. System.out.println(user2);
  11. System.out.println(user==user2);
  12. session.close();
  13. session2.close();
  14. }

观察结果:发现发送了两条sql语句

Mybatis学习笔记03 - 图10

结论:每个SqlSession中的缓存相互独立

  1. sqlsession相同,查询条件不同
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. User user =mapper.queryUserById(1);
  6. System.out.println(user);
  7. System.out.println("============================");
  8. User user2=mapper.queryUserById(2);
  9. System.out.println(user2);
  10. System.out.println(user==user2);
  11. sqlSession.close();
  12. }

观察结果发现发送了两条SQL语句:

Mybatis学习笔记03 - 图11

  1. sqlsession相同,两次查询之间执行了增删改操作

增加方法:

  1. //修改用户
  2. int updateUser(Map map);

编写mapper:

  1. <update id="updateUser" parameterType="map">
  2. update user set name=#{name} where id=#{id}
  3. </update>

测试:

  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. User user =mapper.queryUserById(1);
  6. System.out.println(user);
  7. System.out.println("============================");
  8. HashMap map = new HashMap();
  9. map.put("name","jcsune");
  10. map.put("id",4);
  11. mapper.updateUser(map);
  12. User user2 =mapper.queryUserById(1);
  13. System.out.println(user2);
  14. System.out.println(user==user2);
  15. sqlSession.close();
  16. }

结果:

Mybatis学习笔记03 - 图12

观察结果:查询在中间执行了增删改操作后,重新执行了

结论:因为增删改操作可能会对当前数据产生影响

  1. sqlsession相同,手动清理了一级缓存
  1. @Test
  2. public void testQueryUserById(){
  3. SqlSession session = MybatisUtils.getSession();
  4. UserMapper mapper = session.getMapper(UserMapper.class);
  5. User user = mapper.queryUserById(1);
  6. System.out.println(user);
  7. //手动清除缓存
  8. session.clearCache();
  9. User user2 = mapper2.queryUserById(1);
  10. System.out.println(user2);
  11. System.out.println(user==user2);
  12. session.close();
  13. session2.close();
  14. }

结果:

Mybatis学习笔记03 - 图13

一级缓存就是一个map

3.3 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据诶保存到二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取内容
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中

使用步骤:

  1. 开启全局缓存【Mybatis-config.xml】
  1. <setting name="cacheEnabled" value="true"/>
  1. 去mapper.xml中配置使用二级缓存【UserMapper.xml】
  1. <cache/>
  2. 官方示例=====>查看官方文档
  3. <cache
  4. eviction="FIFO"
  5. flushInterval="60000"
  6. size="512"
  7. readOnly="true"/>
  8. 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
  1. 代码测试
  • 所有的实体类应先实现序列化接口
  1. public class User implements Serializable {
  2. ......
  3. }
  • 测试代码
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. SqlSession sqlSession2 = MybatisUtils.getSqlSession();
  5. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  6. UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
  7. User user =mapper.queryUserById(1);
  8. System.out.println(user);
  9. sqlSession.close()
  10. System.out.println("============================");
  11. User user2=mapper2.queryUserById(1);
  12. System.out.println(user2);
  13. System.out.println(user==user2);
  14. sqlSession2.close();
  15. }
  1. 结果

Mybatis学习笔记03 - 图14

结论:

  • 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
  • 查出的数据都会默认先放在一级缓存中
  • 只有会话提交或关闭以后,一级缓存中的数据才会转到二级缓存中

3.4 缓存原理

Mybatis学习笔记03 - 图15

缓存说白了就是提高查询的效率