Mybatis

Mybatis

1.什么是Mybatis

  • MyBatis是一款优秀的持久层框架
  • 它支持定制化SQL,存储过程以及高级映射
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和java的POJO(Plain Old Java Object,普通老式java对象)为数据库中的记录
  • MyBatis本是apache的一个开源iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis
  • 2013年11月迁移到Github

如何获得Myabtis?

  • mavan仓库:
<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>

2.第一个Mybatis程序

思路:搭建环境–>导入Mybatis–>编写代码–>测试!

1.从 XML 中构建 SqlSessionFactory,得到sqlSession对象

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易

private static SqlSessionFactory sqlSessionFactory;

     static {
        try {
            //使用Mybatis第一步:获取sqlSessionFactory;
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获得SqlSession的实例,SqlSession完全包含了面向数据库执行SQL命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

2.配置MyBatis 系统的核心设置

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 XML 配置文件的详细内容,这里先给出一个简单的示例

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/dragon/dao/UserMapper.xml" />
    </mappers>
</configuration>

3.写Sql语句

<?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">

<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.dragon.dao.UserDao">

    <!--select查询语句-->
    <select id="getUserList" resultType="com.dragon.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

4.在mavan的build中配置resources,来防止我们的资源导出失败的问题

<!--在build中配置resources,来防止我们的资源导出失败的问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

5.编写测试类

@Test
    public void test(){
        //第一步:获得sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一:getMapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userList = mapper.getUserList();

        //方式二:不建议
        //List<User > userList = sqlSession.selectList("com.dragon.dao.UserDao.getUserList");

        for (User user : userList) {
            System.out.println(user);
        }

        //关闭sqlSession
        sqlSession.close();
    }

3.CRUD

1.namespace

namespace 中的包名要和 Dao/Mapper 接口的包名一致!

2.select

选择,查询语句:

  • id:就是对应的namespace中的方法名
  • resultType:Sql语句执行的返回值!
  • parameterType:参数类型!
  1. 编写接口
  2. 编写对应的mapper的sql语句
  3. 测试

insert/update/delete…同上

注意:增删改中必须要提交事务

3.万能的Map

假设,我们的实体类,或者数据库中的表,字段或则参数过多,我们应当考虑优先使用Map!

	//insert一个用户
    int addUser(Map<String, Object> map);
    <!--insert用户-->
    <!--对象用的属性,可以直接取出来,  传递map的key-->
    <insert id="addUser" parameterType="map">
        insert into user (user.name,password) values (#{name},#{password})
    </insert>
	@Test
    public void addUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "wangwu");
        map.put("password", "444444");

        int i = mapper.addUser(map);
        if (i > 0) {
            System.out.println("success!");
        } else {
            System.out.println("no!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

4.模糊查询

直接在sql中拼接通配符!

select * from user where name like "%"#{value}"%"

4.配置解析

4.1 核心配置文件

<?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>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/dragon/dao/UserMapper.xml" />
        <!--<mapper class="com.dragon.dao.UserDao"/>-->
    </mappers>
</configuration>
  • Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息。
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
dathuangabaseIdProvider(数据库厂商标识)
mappers(映射器)

4.2 属性(properties)

在核心配置文件中引入外部properties

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

    <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>

4.3 类型别名(typeAliases)

  • 类型别名是为了java类型设置一个短名字,减少代码冗余
  <typeAliases>        
      <typeAlias type="com.dragon.pojo.User" alias="User"/>    
  </typeAliases>
  • 也可以指定一个包名,Mybatis会在包名下面搜索需要的java Bean,比如:
  • 扫描实体类的包,它的默认别名就为这个类的 类名首字母小写
    <typeAliases>
        <package name="com.dragon.pojo"/>
    </typeAliases>

注意:在实体类少的时候用第一种。

​ 多的时候用第二种。

​ 第一种可以DIY别名,第二种不行。

  1. 也可以用注解别名

直接在实体类上@Alias(“别名”)

@Alias(“user”)
public class User{}

4.4 映射器(mappers)

方法一:使用相对于类路径的资源引用

<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/dragon/dao/UserMapper.xml" />
    </mappers>

方法二:使用class文件绑定注册

    <mappers>
        <mapper class="com.dragon.dao.UserMapper" />
    </mappers>

注意:

  • 接口和它的Mapper配置文件必须同名!
  • 接口和它的Mapper配置文件必须在同一包下!

方法三:使用扫描包进行注入绑定

    <mappers>
        <package name="com.dragon.dao" />
    </mappers>

注意:

  • 接口和它的Mapper配置文件必须同名!
  • 接口和它的Mapper配置文件必须在同一包下!

4.5 设置(settings)

logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
5.1 STDOUT_LOGGING标准日志输出

在Mybatis核心配置中,配置我们的日志!

    <!--设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
5.2 Log4j

maven导入依赖

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

配置文件中配置log4j

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

创建properties文件 设置相关Log4j(网上去查找)

5.分页

5.1 使用Limit分页

分页为了减少数据的处理量

使用Limit分页

语法:select * from user limit startIndex,pageSize
    select * from user limit 2,2;  #[0,n]

5.2 RowBounds分页

不用再使用SQL实现分页

  1. 接口

    List<User> getUserRowBounds();
    
  2. mapper.xml

    <select id="getUserRowBounds" resultType="user">
        select * from user
    </select>
    
  3. 测试

    public void getUserRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //RouBounds实现
        RouBounds rowBounds = new RouBounds(2,2);
        
        //通过java代码层面实现分页
        List<User> userList = sqlSession.selectList("com.dragon.dao.UseeMapper.getUserRowBounds"null,rouBounds);
        
        for (User user : userList){
            System.out.println(user);
        }
        sqlSession.close();
    }
    

6. 使用注解开发

6.1 Mybatis自带注解

增删改查注解开发:不需要再创建mapper文件了,可以直接再接口上完成简单的sql语句

    @Select("select * from emp")
    List<Emp> allEmp();

    @Insert("insert into emp (ename,job,deptno,sal,hiredate) value(#{ename},#{job},#{deptno},#{sal},#{hiredate})")
    int insertEmp(Emp emp);

    @Update("update emp set ename=#{ename} where empno=#{empno}")
    int updateEmp(Emp emp);

    @Delete("delete from emp where empno=#{empno}")
    int deleteEmp(int empno);
注解目标相应的XML描述
@CacheNamespace为给定的命名空间(比如类)配置缓存。属性:implemetation,eviction,flushInterval , size 和 readWrite 。
@CacheNamespaceRef参照另外一个命名空间的缓存来使用。属性:value,也就是类的完全限定名。
@ConstructorArgs方法

7.Lombok

  1. 在idea中下载插件

  2. 到maven的依赖

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
    
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var

8. 结果集映射

为了处理数据库的字段名和实体类属性名不同,显式使用外部的 resultMap 会怎样

<resultMap id="userResultMap" type="User">
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

<select id="selectUsers" resultMap="userResultMap">
  select *
  from user
  where id = #{id}
</select>

注意:id就是对应resultMap的值

结果映射(resultMap)
  • constructor
    

    - 用于在实例化类时,注入结果到构造方法中

    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能

  • result – 注入到字段或 JavaBean 属性的普通结果

  • association
    

    – 一个复杂类型的关联;许多结果将包装成这种类型

    • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
  • collection
    

    – 一个复杂类型的集合

    • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
  • discriminator
    

    – 使用结果值来决定使用哪个

    resultMap
    
    • case
      

      – 基于某些值的结果映射

      • 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

8.1 多对一

按照查询嵌套处理

  • 相当于sql中的子查询
	<!--查询出来所有学生信息,然后根据tid查老师-->
    <select id="getStudent" resultMap=" studentTeacher">
        select * from student
    </select>

    <resultMap id="studentTeacher" type="student">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <!--复杂的属性我们需要单独处理 对象:association 集合:collection -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

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

按照结果嵌套处理

  • 相当于sql中的连表查询
    <!--按照结果嵌套处理-->
    <select id="getStudent2" resultMap="studentTeacher2">
        select s.id sid,s.name sname,t.name tname
        from student s,teacher t
        where s.tid=t.id
    </select>
    <resultMap id="studentTeacher2" type="student">
        <result column="sid" property="id"/>
        <result column="sname" property="name"/>
        <association property="teacher" javaType="teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

8.2一对多

比如:一个老师拥有多个学生

对于老师而言,就是一对多的关系!

  1. 环境搭建

实体类

public class Student {
    private int id;
    private String name;
    private int tid;
}

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

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

按照结果嵌套处理

<select id="getTeacher" resultMap="tStudents">
        select t.id tid,t.name tname,s.id sid,s.name sname
        from student s,teacher t
        where s.tid = t.id
    </select>
    <resultMap id="tStudents" type="teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--
        复杂的属性,我们需要单独处理 集合:collection
        javaType="" 指定属性的类型!
        集合中的泛型信息,我们使用ofType获取
        -->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>

按照查询嵌套处理

<!--按照查询嵌套处理-->
    <select id="getTeacher2" resultMap="tStudents2">
        select * from teacher where id=#{tid}
    </select>
    <resultMap id="tStudents2" type="teacher">
        <collection property="students" javaType="ArrayList" ofType="student" select="getStudents" column="id"/>
    </resultMap>
    <select id="getStudents" resultType="student">
        select * from student where tid=#{tid}
    </select>

小结

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

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段命名的问题!
  • 弱国问题不好排查错误,可以使用日志,建议Log4j

9. 动态SQL

什么是动态SQL:动态SQL就是值根据不同的条件生成不同的SQL语句

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

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

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

if

接口

	//查询学生
    public List<Student> getStudents(Map map);

sql映射

	<select id="getStudents" resultType="student" parameterType="map">
        select * from student where id=2
        <if test="id != null">
            or id=#{id}
        </if>
        <if test="name != null">
            or name=#{name}
        </if>
    </select>

这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)

小结:简单理解if中的test中的值代表判断语句,然后再加入动态sql语句

choose (when, otherwise)

相当于java中的swith,case,default语句

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

trim (where, set)

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

注意,我们覆盖了后缀值设置,并且自定义了前缀值。

where

重点where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

简单来说也就是where这个标签,会帮助我们解决if中选择语句是and和or的不便之处,判断需不需要where

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>
set

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片段

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

  1. 使用SQL标签抽取公共部分

    id需要对应的include

    <sql id="if-id-name">
        <if test="id != null">
            or id=#{id}
        </if>
        <if test="name != null">
            or name=#{name}
        </if>
    </sql>
    
  2. 再需要使用的地方使用include标签应用出来

    refid对应上边的id属性

<include refid="if-id-name"></include>

Foreach

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

  • sql映射
    <select id="getStudents" resultType="student" parameterType="map">
        select * from student where id
        <foreach collection="ids" item="id" open="in(" separator="," close=")">
            #{id}
        </foreach>
    </select>
  • 测试
    @Test
    public void getStudents() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        HashMap map = new HashMap();
        ArrayList<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(2);
        ids.add(3);

        map.put("ids", ids);

        List<Student> students = mapper.getStudents(map);
        for (Student student : students) {
            System.out.println(student);
        }
        sqlSession.close();
    }

10. 缓存

查询: 连接数据库,耗资源

​ 一次查询的结果,给他暂存在一个可以直接取到的地方! -----> 内存 :缓存

当我们再次查询相同数据的时候,直接走缓存,就不需要走数据库了。

10.1 简介

  1. 什么是缓存[Cache]?
    • 存在内存中的临时数据。
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询。从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
  2. 为什么使用缓存?
    • 减少和数据库的交互次数,减少系统开销,提高系统效率。
  3. 什么样的数据能使用缓存?
    • 经常查询并且部经常改变的数据。 【可以使用缓存】

10.2 Mybatis缓存

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

10.3 一级缓存

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

测试步骤:

  1. 开启日志!
  2. 测试再一个Session中查询两次相同记录
  3. 查看日志输出

缓存失效的情况:

  1. 查询不同的东西

  2. 增删改操作,可能会改变原来的数据,所以比顶会刷新缓存!

  3. 查询不同的Mapper.xml

  4. 手动清理缓存!

    sqlSession.clearCache();//手动清理缓存
    

小结:一级缓存默认是开启的,只在一次sqlSession中有效,也就是拿到连接到关闭这个去区间段!

一级缓存就是一个Map。

10.4 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存。
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据会被保存到二级缓存中;
    • 新的会话查询信息,就可以直接从二级缓存中获取内容;
    • 不同的namespace查出的数据会放在自己对应的缓存(map)中;

1.开启全局缓存,在配置中setting中显示缓存

<setting name="cacheEnabled" value="true"/>

2.在sql映射中自定义缓存Cache的参数

<!--在当前Mapper.xml中使用二级缓存-->
<cache eviction="FIFO"
       fulshInterval="60000"
       size="512"
       readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU

小结:

  • 只要开启二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级换内存中;
  • 只有当会话提交,或则关闭的时候,才会提交到二级缓存中!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值