Mybatis基础使用

Mybatis

1. 简介

mybatis框架主要是围绕着SqlSessionFactory进行的,创建过程大概如下:

(1)、定义一个Configuration对象,其中包含数据源、事务、mapper文件资源以及影响数据库行为属性设置settings

(2)、通过配置对象,则可以创建一个SqlSessionFactoryBuilder对象

(3)、通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例。

(4)、SqlSessionFactory 的实例可以获得操作数据的SqlSession实例,通过这个实例对数据库进行操作

2. Mybatis详细执行流程(注意理解)

  1. Resources获取全局配置文件(例如 mybatis-config.xml)
  2. 实例化SqlSessionFactoryBulider构造器
  3. 解析配置文件流XMLConfigBulider
  4. Configuration所有的配置信息
  5. SqlSessionFactory实例化
  6. transaction事务管理
  7. 创建executor执行器
  8. 创建sqlSession
  9. 实现CRUD
  10. 提交事务
  11. 关闭

3. CRUD

(增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete))

< 开发步骤 >:

  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 白那些Mapper.xml
  5. 测试
  1. 编写接口(UserDao.java/UserMapper.java)

    //添加用户
    int addUser(User user);
    
  2. 编写对应的mapper中的sql语句 (UserMapper.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">
    <!--namespace绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.gtl.dao.UserDao">
        <insert id="addUser" parameterType="com.gtl.pojo.User">
            insert into test.user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address})
        </insert>
    </mapper>
    
  3. 测试 (UserDaoTest.java)

    @Test
        public void addUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            int res = userDao.addUser(new User(7,"桔梗","2021/1/8","女","广州"));
            if(res > 0){
                //提交事务,如果不提交,数据库不会发生改变
                sqlSession.commit();
                System.out.println("插入成功!");
            }
            sqlSession.close();
        }
    
    注意:增删改需要提交事务 sqlSession.commit();
  • namespace

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

  • Select(选择、查询)

 <select id="getUserList" resultType="com.gtl.pojo.User">
    select * from test.user
 </select>
 <select id="getUserById" parameterType="int" resultType="com.gtl.pojo.User">
    select * from test.user where id = #{id}
 </select>

共有三个参数:

  • id:就是对应namespace中的方法名
  • parameterType: 参数类型
  • resultType:Sql语句执行的返回值
  • Insert

<insert id="addUser" parameterType="com.gtl.pojo.User">
  insert into test.user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address})
</insert>
  • Update

<update id="updateUser" parameterType="com.gtl.pojo.User">
   update test.user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id = #{id}
</update>
  • Delete

<delete id="deleteUser" parameterType="int">
   delete from test.user where id=#{id}
</delete>

UserDao/UserMapper

package com.gtl.dao;

import com.gtl.pojo.User;

import java.util.List;

public interface UserDao {
    List<User> getUserList();
    User getUserById(int id);
    int addUser(User user);
    int updateUser(User user);
    int deleteUser(int id);
}

4. 配置解析

1. 核心配置文件

2. 环境配置

Mybatis可以配置成适应多种环境

但是要记住:尽管可以配置多种环境,但是SqlSessionFactory实例只能选择一种环境

  • Mybatis的默认的事务管理器就是JDBC
  • 连接池:POOLED

3. 属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z5xNIne2-1627011381186)(image-20210119113834782.png)]

4. 类型别名

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {
    ...
}

5. 其他配置

6. 映射器(mapper)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 -->   
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

5. 生命周期和作用域

理解我们之前讨论过的不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。


提示 对象生命周期和依赖注入框架

依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。


SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory
  • 可以想象成数据库连接池

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5FQkySK-1627011381189)(image-20210119121720428.png)]

6.解决属性名和字段名不一致的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S1CaiW9O-1627011381190)(image-20210121120329136.png)]

解决方法:
  • 起别名

     <select id="getUserList" resultType="com.gtl.pojo.User">
            select id,name,pwd as password from test.user
     </select>
    
  • 结果集映射(resultMap)

    id name password
    id name pwd
    
    <!--结果集映射-->
    <resultMap id="UserMap" type="User">
        <!--column(数据库中的字段),property(实体类中的属性)-->
    	<result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="possword"/>
    </resultMap>
    
     <select id="getUserList" resultMap="UserMap">
            select * from test.user where id=#{id}
     </select>
    
  • resultMap 元素是 MyBatis 中最重要最强大的元素。

7. 日志

Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging
7.1 自带的日志工厂
<settings>
	<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrpOIzhn-1627011381191)(image-20210121185333833.png)]

7.2 LOG4J的使用

8.分页

为什么要分页?

  • 减少数据的处理量
  • 使用Limit分页
//直接使用sql语法
语法:
select * from user limit startindex,pagesize;
  • 使用Mybatis分页 (公司常用)

    步骤:

    1. 接口
    2. Mapper.xml
    3. 测试
//UserMapper.java
public interface UserMapper {
    List<User> getUserByLimit(Map<String,Integer> map);
}
//UserMapper.xml
<select id="getUserByLimit" resultType="map">
    select * from mbdemo_db.user limit #{startIndex},#{pageSize}
 </select>
 @Test
    public void getUseerByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlsession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String,Integer> map = new HashMap<String, Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userList = userMapper.getUserByLimit(map);
    }
  • 通过RowBounds(了解,过时了不常用)

9.使用注解开发

本质:反射原理实现

底层:动态代理

  1. 注解在接口上实现
  2. 需要在核心配置文件中绑定接口

10. lombok插件

简化开发的

11.多对一

  • 测试环境搭建

    1.分别为数据库的表创建相应的实体类
    2.分别建立mapper接口和对应的mapper。xml文件

    @Data
    public class Student {
        private int id;
        private String name;
        private Teacher teacher;
    }
    
    @Data
    public class Teacher {
        private int tid;
        private String name;
    }
    
  • 处理方法
    • 注意
    一般的结果集映射用 <result>即可,但是复杂的属性,我们需要单独处理。
    对象-----------<association>
    集合-----------<collection>
    
    • 按照查询嵌套处理(原理是 “子查询”)
      <select id="getStudent"  resultMap="STUTEA">
      	select * from mbdemo_db.student
      </select>
      <resultMap id="STUTEA" type="com.logdemo3.pojo.Student">
      	<result column="id" property="id"/>
      	<result column="name" property="name"/>
          
      <association property="teacher" column="tid" javaType="com.logdemo3.pojo.Teacher" select="getTeacher"/>
      	</resultMap>
      <select id="getTeacher" resultType="com.logdemo3.pojo.Teacher">
          <!--注意这里的tid的参数可以是随意值-->
          <!--因为查询是一条一条执行的,当执行到tid时去调用映射,映射又去子查询,所以#{}里面自动填充了column的值,所以可以随便填-->
      	select * from mbdemo_db.teacher where tid=#{tid}
      </select>
      
    • 按照结果嵌套处理(“联表查询”)
      <!--  按照结果嵌套查询  -->
          <select id="getStudent1" resultMap="stutea">
              select student.id sid,student.name sname,teacher.tid teaid,teacher.name tname from student,teacher
              where student.tid=teacher.tid;
          </select>
          <resultMap id="stutea" type="com.logdemo3.pojo.Student">
              <result property="id" column="sid"/>
              <result property="name" column="sname"/>
              <association property="teacher" javaType="com.logdemo3.pojo.Teacher">
                  <result property="tid" column="teaid"/>
                  <result property="name" column="tname"/>
              </association>
          </resultMap>
      
    • 运行结果

      PooledDataSource forcefully closed/removed all connections.
      PooledDataSource forcefully closed/removed all connections.
      PooledDataSource forcefully closed/removed all connections.
      PooledDataSource forcefully closed/removed all connections.
      Opening JDBC Connection
      Created connection 1413246829.
      Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@543c6f6d]
      ==>  Preparing: select student.id sid,student.name sname,teacher.tid teaid,teacher.name tname from student,teacher where student.tid=teacher.tid; 
      ==> Parameters: 
      <==    Columns: sid, sname, teaid, tname
      <==        Row: 1, 北卡罗来, 1, 马老师
      <==        Row: 2, 俾斯麦, 1, 马老师
      <==        Row: 3, 衣阿华, 1, 马老师
      <==        Row: 4, 格奈森瑙, 2, 张老师
      <==      Total: 4
      Student(id=1, name=北卡罗来, teacher=Teacher(tid=1, name=马老师))
      Student(id=2, name=俾斯麦, teacher=Teacher(tid=1, name=马老师))
      Student(id=3, name=衣阿华, teacher=Teacher(tid=1, name=马老师))
      Student(id=4, name=格奈森瑙, teacher=Teacher(tid=2, name=张老师))
      Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@543c6f6d]
      Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@543c6f6d]
      Returned connection 1413246829 to pool.
      
      Process finished with exit code 0
      

12. 一对多

  • 环境搭建
    @Data
    public class Teacher {
        private int tid;
        private String name;
        private List<Student> students;
    }
    
    @Data
    public class Student {
        private int id;
        private String name;
        private int tid;
    }
    
  • 实现(按结果查询)
    • javaType & ofType
      • javaType 用于指定实体类中属性的类型
      • ofType 用于指定映射到List或者集合中的pojo类型
    <select id="getStudent" resultMap="STUTEA">
        select student.id sid,student.name sname,teacher.tid teaid,teacher.name tname
        from teacher,student
        where student.tid = teacher.tid and teacher.tid=#{tid}
    </select>
    <resultMap id="STUTEA" type="com.logdemo4.pojo.Teacher">
        <result property="tid" column="teaid"/>
        <result property="name" column="tname"/>
        <collection property="students" ofType="com.logdemo4.pojo.Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="teaid"/>
        </collection>
    </resultMap>
    
    运行结果
    Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    Opening JDBC Connection
    Created connection 770189387.
    Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2de8284b]
    ==>  Preparing: select student.id sid,student.name sname,teacher.tid teaid,teacher.name tname from teacher,student where student.tid = teacher.tid and teacher.tid=? 
    ==> Parameters: 1(Integer)
    <==    Columns: sid, sname, teaid, tname
    <==        Row: 1, 北卡罗来, 1, 马老师
    <==        Row: 2, 俾斯麦, 1, 马老师
    <==        Row: 3, 衣阿华, 1, 马老师
    <==      Total: 3
    Teacher(tid=1, name=马老师, students=[Student(id=1, name=北卡罗来, tid=1), Student(id=2, name=俾斯麦, tid=1), Student(id=3, name=衣阿华, tid=1)])
    Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2de8284b]
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2de8284b]
    Returned connection 770189387 to pool.
    
    Process finished with exit code 0
    
    

13. 动态SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

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

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

14. 缓存

之前的查询每次都要连接数据库,很耗费资源和时间。 查询----连接数据库
缓存----就是将一次查询得结果暂存在内存中
  1. 什么是缓存(cache)
    • 存在内存中的临时数据
    • 将用户经常使用的数据放在缓存中,用户去查询数据是就不用从磁盘上数据库文件中查询了,从缓存中查询,可以大大提高查询效率,解决了高并发系统的性能问题
  • 为什么使用缓存

    • 减少数据库交互次数,减少系统开销,提高系统效率
  • 什么样的数据需要使用缓存

    • 经常查询,并且不怎么改变的数据

    14.1 MyBatis缓存

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

    14.2 一级缓存

    • 缓存失效的情况
      1. 查询不同的东西
      2. 增删改操作会,可能会改变原来的数据,所以必定会刷新缓存
      3. 查询不同Mapper.xml
      4. 手动清理缓存(sqlSession.clearcaChe())
    • 小结:一级缓存是默认开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个时间段里面有效

    14.3 二级缓存(全局缓存)

    • 二级缓存又叫做全局缓存,一级缓存作用域太低,所以诞生了二级缓存
    • 基于namespace级别的缓存,一个命名空间对应一个二级缓存
    • 工作机制
      • 一个会话查询一条数据,这跳水会被放在当前以及缓存中
      • 如果当前会话关闭,这个会话对应的一级缓存就会消失,但我们想要的是,会话关闭了,一级缓存中的数据被保存在二级缓存中
      • 新的会话就可以在二级缓存中查找信息
      • 不同的mapper查询出来的数据会放在自己对应的缓存(map)中
    cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
    <!-- 显式的开启缓存-->
    <setting name="cacheEnabled" value=“true”/>
    
  • 实例

    @Test
        public void getUserById(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user1 = userDao.getUserById(3);
            System.out.println(user1);
            sqlSession.close();
    
            SqlSession sqlSession2 = MybatisUtils.getSqlSession();
            UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
            User user2 = userDao2.getUserById(3);
            System.out.println(user2);
            sqlSession.close();
    
        }
    
    <!-- mapper.xml-->
    <mapper namespace="com.gtl.dao.UserDao">
        <cache
                    eviction="FIFO"
                    flushInterval="60000"
                    size="512"
                    readOnly="true"/>
        <select id="getUserById" parameterType="int" resultType="com.gtl.pojo.User" useCache="true">
            select * from test.user where id = #{id}
        </select>
    <mapper/>
        
        //注意select标签里面的 useCache 属性
    
    Cache Hit Ratio [com.gtl.dao.UserDao]: 0.0
    Opening JDBC Connection
    Created connection 1337344609.
    Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4fb64261]
    ==>  Preparing: select * from test.user where id = ? 
    ==> Parameters: 3(Integer)
    <==    Columns: id, username, birthday, sex, address
    <==        Row: 3, 小二王, 2018-03-04 11:34:34.0, 女, 北京金燕龙
    <==      Total: 1
    User{id=3, username='小二王', birthday='2018-03-04 11:34:34.0', sex='女', address='北京金燕龙'}
    Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4fb64261]
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4fb64261]
    Returned connection 1337344609 to pool.
    Cache Hit Ratio [com.gtl.dao.UserDao]: 0.5
    User{id=3, username='小二王', birthday='2018-03-04 11:34:34.0', sex='女', address='北京金燕龙'}
    
    //可以看出,因为二级缓存的存在,所以数据的开启和关闭只进行了一次
    
  • 小结
    • 只要开启了二级缓存,在同一个mapper下的就有效
    • 所有数据都会先放在一级缓存中
    • 当会话提交或者关闭时,才会提交到二级缓存中
  • 缓存原理
    缓存顺序:
    1.先看二级缓存
    2.再看一级缓存
    3.查询数据库
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4FAvqA1-1627011381193)(image-20210203142544018.png)]

  • 补充

    默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

    <cache/>
    

    基本上就是这样。这个简单语句的效果如下:

    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
    • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
    • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
    • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
    • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

    提示 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。

    这些属性可以通过 cache 元素的属性来修改。比如:

    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    

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

    可用的清除策略有:

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

    默认的清除策略是 LRU。

  • 自定义缓存(EhCache)

te 和 delete 语句会刷新缓存。

  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

提示 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。

这些属性可以通过 cache 元素的属性来修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

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

可用的清除策略有:

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

默认的清除策略是 LRU。

  • 自定义缓存(EhCache)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值