Mybatis学习笔记(下)

Mybatis

10.多对一处理

多个学生对应一个老师

对于学生而言,关联:多个学生关联一个老师【多对一】

对于老师而言,集合,一个老师有很多学生【一对多】

在数据库中创建表:

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO teacher(`id`, `name`) 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` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

测试环境搭建:

项目结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f7hICMgT-1598064784808)(C:\Users\Tyrion\AppData\Roaming\Typora\typora-user-images\image-20200819161951529.png)]

1.导入lombok

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>

2.新建实体类Teacher Student

package com.tyrion.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;

    //学生需要关联一个老师
    private Teacher teacher;
}
package com.tyrion.pojo;

import lombok.Data;

@Data
public class Teacher {
    private int id;
    private String name;
}

3.建立Mapper接口

4.建立Mapper.xml文件

5.在配置文件中绑定Mapper接口或文件【多种方式】

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration核心配置文件-->
<configuration>

<!--    引入外部配置文件-->
    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <typeAliases>
        <package name="com.tyrion.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>


<!--    绑定接口-->
    <mappers>
        <mapper class="com.tyrion.dao.TeacherMapper"/>
        <mapper class="com.tyrion.dao.StudentMapper"/>
    </mappers>

</configuration>

6.测试

按照查询嵌套处理

需求:查询所有学生和所对应的老师的信息

1.StudentMapper.java

package com.tyrion.dao;

import com.tyrion.pojo.Student;

import java.util.List;

public interface StudentMapper {

    //查询所有的学生的信息以及对应的老师信息
    public List<Student> getStudent();
}

2.StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tyrion.dao.StudentMapper">


<!--
    思路:
    1.查询所有的学生信息
    2.根据查询出来的学生的tid,寻找对应的老师
    3.
-->
    <resultMap id="StudentTeacher" 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="getStudent" resultMap="StudentTeacher">
        select * from mybatis.student
    </select>

    <select id="getTeacher" resultType="teacher">
        select * from mybatis.teacher where id=#{id}
    </select>

</mapper>

按照结果嵌套处理

<!--方式二:按照结果嵌套处理
    -->
    <resultMap id="StudentTeacher2" type="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid, s.name sname, t.name tname
        from mybatis.student s,mybatis.teacher t
        where s.tid=t.id
    </select>

回顾Mysql多对一查询方式:

  • 子查询
  • 联表查询

11.一对多处理

首先需要修改实体类

package com.tyrion.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
package com.tyrion.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;

    //一个老师可以有多个学生
    private List<Student> students;
}

按照结果嵌套查询

接口

package com.tyrion.dao;

import com.tyrion.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface TeacherMapper {

    //获取指定老师下的所有学生及该老师信息
    Teacher getTeacher(@Param("tid") int id);
}

xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tyrion.dao.TeacherMapper">


<!--    按照结果嵌套查询-->
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--        javaType:指定属性的类型
            集合中的泛型信息,我们使用ofType获取
-->
        <collection property="students" ofType="student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from mybatis.teacher t,mybatis.student s
        where s.tid=t.id and t.id=#{tid}
    </select>
</mapper>

测试:

import com.tyrion.dao.TeacherMapper;
import com.tyrion.pojo.Teacher;
import com.tyrion.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class Mytest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
//返回值
//Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
        sqlSession.close();
    }
}

按照查询嵌套查询

xml:

<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from mybatis.teacher where id=#{tid}
</select>

<resultMap id="TeacherStudent2" type="teacher">
    <collection property="students" javaType="ArrayList" ofType="student" select="getStudentByTeacherId" column="id"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="student">
    select * from mybatis.student where tid=#{tid}
</select>

小结

  1. 关联 -association 【多对一】
  2. 集合 -collection 【一对多】
  3. javaType:用来指定实体类中属性的类型
  4. ofType:用来指定映射到List或集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证SQL可读性,保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果问题不好排查,可以使用日志(建议log4j)

12.动态SQL

根据不同的条件生成不同的SQL语句

  如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis  之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3  替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
  
  - if
  - choose (when, otherwise)
  - trim (where, set)
  - foreach

搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8;

建立工程:

  1. 导包

  2. 编写配置文件

  3. 编写实体类

    package com.tyrion.pojo;
    
    import lombok.Data;
    
    import java.util.Date;
    
    @Data
    public class Blog {
        private int id;
        private String title;
        private String author;
        private Date creatTime;
        private int views;
    }
    
  4. 编写实体类对应的Mapper接口和Mapper.xml

    package com.tyrion.dao;
    
    import com.tyrion.pojo.Blog;
    
    public interface BlogMapper {
    
        //插入数据
        int addBook(Blog blog);
    }
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.tyrion.dao.BlogMapper">
    
        <insert id="addBook" parameterType="blog">
            insert into mybatis.blog (id, title, author, create_time, views)
            values (#{id},#{title},#{author},#{createTime},#{views});
        </insert>
    
    </mapper>
    
    1. 测试
    import com.tyrion.dao.BlogMapper;
    import com.tyrion.pojo.Blog;
    import com.tyrion.utils.IDUtils;
    import com.tyrion.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.Date;
    
    public class Mytest {
        @Test
        public void addInitBlog(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
            Blog blog=new Blog();
            blog.setId(IDUtils.getId());
            blog.setTitle("Mybatis so easy");
            blog.setAuthor("kaung");
            blog.setCreateTime(new Date());
            blog.setViews(999);
            mapper.addBook(blog);
    
            blog.setId(IDUtils.getId());
            blog.setTitle("java so easy");
            mapper.addBook(blog);
    
            blog.setId(IDUtils.getId());
            blog.setTitle("spring so easy");
            mapper.addBook(blog);
    
            blog.setId((IDUtils.getId()));
            blog.setTitle("service so easy");
            mapper.addBook(blog);
    
            //已经在工具类中打开自动提交事务,所以此处无需手动commit
            sqlSession.close();
        }
    }
    

IF

  1. 接口
//查询博客
List<Blog> queryBlogIf(Map map);
  1. xml文件
<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog where 1=1
    <if test="title!=null">
        and title=#{title}
    </if>
    <if test="author!=null">
        and author=#{author}
    </if>
</select>
  1. 测试
@Test
public void queryBlogIf(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap map = new HashMap();
    map.put("title","Mybatis so easy");
    List<Blog> blogs = mapper.queryBlogIf(map);

    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

choose (when, otherwise)

choose标签和java中的switch语句相似,可以用于多个中选择一个的场景,when相当于其中某一情况,otherwise相当于default情况

  1. 接口
//选择条件查询博客
List<Blog> queryBlogChoose(Map map);
  1. xml文件
<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title!=null">
                title=#{title}
            </when>
            <when test="author!=null">
                and author=#{author}
            </when>
            <otherwise>
                and views=#{views}
            </otherwise>
        </choose>
    </where>
</select>
  1. 测试
@Test
public void queryBlogChoose(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap map = new HashMap();
    map.put("views",999);
    map.put("title","java so easy");
    List<Blog> blogs = mapper.queryBlogChoose(map);

    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

trim (where, set)

where

在if的案例中,借助where 1=1保证了后面的语句在第一个if不满足时,后面拼接上来的and也满足sql语法条件

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog where 1=1
    <if test="title!=null">
        title=#{title}
    </if>
    <if test="author!=null">
        and author=#{author}
    </if>
</select>

此外,我们也可以使用where标签实现这样的功能

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <if test="title!=null">
            and title=#{title}
        </if>
        <if test="author!=null">
            and author=#{author}
        </if>
    </where>
</select>

set

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

接口

//更新博客
int updateBlog(Map map);

xml

<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title!=null">
            title=#{title},
        </if>
        <if test="author!=null">
            author=#{author}
        </if>
    </set>
    where id=#{id}
</update>

测试

@Test
public void updateBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap map = new HashMap();
    map.put("id","f0d687f35c444033b819418f5896ffa5");
    map.put("title","java so easy2");

    mapper.updateBlog(map);


    sqlSession.close();
}

trim

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

set 元素等价的自定义 trim 元素:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便进行复用

  1. 使用标签抽取公共的部分
<sql id="if-title-author">
    <if test="title!=null">
            title=#{title}
        </if>
        <if test="author!=null">
            and author=#{author}
        </if>
</sql>
  1. 在需要使用的地方用进行引用
<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <include refid="if-title-author"/>
    </where>
</select>

注意点:

  • 最好基于单表来定义SQL片段
  • 不要存在标签

foreach

  1. 接口
//foreach测试(测试前,将数据库中的id改为1-4)
List<Blog> queryBlogForeach(Map map);
  1. xml
<!--    select * from mybatis.blog where (id=1 or id=2 or id=3)-->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" open="(" close=")" separator="or">
                id=#{id}
            </foreach>
        </where>
    </select>
  1. 测试
@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(2);
    map.put("ids",ids);

    List<Blog> blogs = mapper.queryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }


    sqlSession.close();
}

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合即可

建议:

  • 先在Mysql中写出对应的SQL
  • 再去修改成为我们的动态SQL

13.缓存

13.1简介

查询:连接数据库,消耗资源
一次查询的结果,暂存到一个可以直接取的地方,即内存

再次查询相同数据时,直接从缓存中取
  1. 什么是缓存(cache)
    • 存在内存中的临时数据
    • 将用户经常查询的数据放在缓存中,用户就不用从磁盘上(关系型数据库文件)查询,从缓存上查询,从而提高查询效率,解决了高并发系统的效率问题
  2. 问什么使用缓存
    • 减少和数据库的交互次数,减少系统开销,提高效率系统
  3. 什么样的数据可以使用缓存
    • 经常查询且不经常改变的数据

13.2Mybatis缓存

  • Mybatis包含一个强大的查询缓存特性,可以非常方便的定制和配置缓存,缓存可以极大的提升查询效率
  • Mybatis系统默认定义了两级缓存,一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(sqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,是基于namespace级别的缓存
    • 为了提高扩展性,Mybatis定义了缓存接口Cache。可以通过实现Cache接口来自定义二级缓存。

13.3一级缓存

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

测试步骤:

  1. 开启日志
  2. 测试在一次SqlSession中查询两次相同的记录
 @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User user = mapper.queryUserById(1);
        System.out.println(user);

        User user1 = mapper.queryUserById(1);
        System.out.println(user1);

        sqlSession.close();
    }
  1. 查看日志输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j52kJc3j-1598064784810)(C:\Users\Tyrion\AppData\Roaming\Typora\typora-user-images\image-20200821161552607.png)]

缓存失效的情况:

  1. 查询不同的东西
  2. 增删改查操作,可能会改变原来的数据,所以必定会刷新缓存
  3. 查询不同的Mapper.xml
  4. 手动清除缓存
sqlSession.clearCache();

小结:

  • 一级缓存默认开启,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段

一级缓存相当于一个map

13.4二级缓存

  • 二级缓存也叫全局缓存,一级缓存的作用域太低了,因此二级缓存诞生
  • 基于namespace级别的缓存,一个名称空间对应一个二级缓存
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是需求是,会话关闭后一级缓存中的内容会被放在二级缓存中
    • 新的会话查询内容就可以从二级缓存中获取内容
    • 不同的Mapper查出的数据会放在自己对应的缓存中

步骤:

  1. 开启全局缓存
	<settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        显式开启全局缓存(默认也是开起的)-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
  1. 在要使用二级缓存的Mapper中开启
<cache
        eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="true"/>

也可以自定义参数

  1. 测试

视频中问题:User类未序列化,但此处测试我并没有出现

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);


    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    User user1 = mapper2.queryUserById(1);
    System.out.println(user1);
    System.out.println(user==user1);

    sqlSession.close();
    sqlSession2.close();
}
 @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession2 = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        sqlSession.close();

        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user1 = mapper2.queryUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);
        sqlSession2.close();
    }

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交或关闭的时候,才会提交到二级缓存中

13.5缓存原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BfYrlOQX-1598064784812)(C:\Users\Tyrion\AppData\Roaming\Typora\typora-user-images\image-20200821201811738.png)]

13.6自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存

要在程序中使用,先要导包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.0</version>
</dependency>

在Mapper.xml文件中进行配置

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在resource文件下建立ehcache.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

PS:如果 xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"处爆红,可以尝试打开 settings - languages&frameworks - schemas and dtds ,添加地址 http://ehcache.org/ehcache.xsd,即可解决问题

实际中常用的缓存策略:Redis数据库 K-V键值对

化,但此处测试我并没有出现

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);


    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    User user1 = mapper2.queryUserById(1);
    System.out.println(user1);
    System.out.println(user==user1);

    sqlSession.close();
    sqlSession2.close();
}
 @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession2 = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        sqlSession.close();

        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user1 = mapper2.queryUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);
        sqlSession2.close();
    }

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交或关闭的时候,才会提交到二级缓存中

13.5缓存原理

[外链图片转存中…(img-BfYrlOQX-1598064784812)]

13.6自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存

要在程序中使用,先要导包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.0</version>
</dependency>

在Mapper.xml文件中进行配置

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在resource文件下建立ehcache.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

PS:如果 xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"处爆红,可以尝试打开 settings - languages&frameworks - schemas and dtds ,添加地址 http://ehcache.org/ehcache.xsd,即可解决问题

实际中常用的缓存策略:Redis数据库 K-V键值对

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值