Mybatis 一边学一遍写下来的笔记

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MInA7Ng1-1620752631550)(assets/mybatis-logo.png)]

1.入门

安装

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

SqlSessionFactory

<?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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="xxxx"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/xue/dao/UserMapper.xml"/>
    </mappers>

</configuration>

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

注意文件的配置

获取 SqlSessionFactory

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

探究已映射的 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">
<mapper namespace="com.xue.dao.UserMapper">
    <select id="getUserList" resultType="com.xue.pojo.User">
        select *
        from mybatis.user
    </select>
</mapper>

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

2.CRUD

命名空间

全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。

XML内的配置

查询

<select id="getUserList" resultType="com.xue.pojo.User">
    select *
    from mybatis.user
</select>

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

增加

<insert id="addUser" parameterType="com.xue.pojo.User" >
    insert into mybatis.user(id, name, password)
        value (#{id}, #{name}, #{password})
</insert>

修改

<update id="updateUser" parameterType="com.xue.pojo.User">
    update mybatis.user
    set name=#{name},
        password=#{password}
    where id = #{id}
</update>

删除

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

测试代码

查询

@Test
public void test() {

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        //获取dao
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();

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

    } finally {
        sqlSession.clearCache();
    }
}
@Test
public void test2() {
    //获取一个连接
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    try {
        //我猜是利用反射来获取 操作方法
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User userById = mapper.getUserById(1);
        System.out.println(userById);
    } finally {
        sqlSession.close();
    }
}

增删改

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

        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            int xue3 = mapper.addUser(new User(1234, "xue3", "123"));
            System.out.println(xue3);
            sqlSession.commit();
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }

通过map来操作

类似于把map内的键和值 直接放了进去
因为之前是用user 如果我们传递一个user进去 类似于传递进去了一个map 我的假设是他穿进去了一个dao层然后呢 利用get来获取到了变量的具体的值 然后变成了map
也可以是我传进去了一个user 然后呢 我利用反射来获取user里的get方法 我岂不是不用map
这都是假设,后面需要从源码来进行分析

这里的

​ #{userid}, #{username}, #{userpassword}

可以随意的控制 只需要在map传递的时候控制好map即可

<insert id="addUser2" parameterType="map" >
    insert into mybatis.user(id, name, password)
        value (#{userid}, #{username}, #{userpassword})
</insert>

这个是测试方法

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

    try {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("userid",123);
        map.put("username","xue6");
        map.put("userpassword","xue6");
        int xue3 = mapper.addUser2(map);
        System.out.println(xue3);
        sqlSession.commit();
    } finally {
        sqlSession.rollback();
        sqlSession.close();
    }
}

模糊查询

<select id="getUserLike" resultType="com.xue.pojo.User">
    select *
    from mybatis.user
    where name like #{value}
</select>

其中访问的时候可以是

@Test
public void test11() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        //获取dao
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserLike("xue%");
        for (User user : userList) {
            System.out.println(user);
        }
    } finally {
        sqlSession.clearCache();
    }
}

3.配置信息*

核心配置

mybatis-config.xml(官方推荐的命名)

configuration(配置)

属性(properties)

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

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

编写一个 db.properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8
username=root
password=xxx

在配置中引入

<properties resource="db.properties">

</properties>

环境配置(environments)

默认设置

<transactionManager type="JDBC"/>
<dataSource type="POOLED">
.....
 </dataSource>

设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。、

设置名描述有效值默认值
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse

类型别名(typeAliases)

类型别名可为 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>
<package name="com.xue.pojo"/>

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

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

插件(plugins)

映射器(mappers)

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

必须要mapper和xml同名 且在一个目录下

<!-- 使用映射器接口实现类的完全限定类名 -->
<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>

这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了,也就是接下来我们要讨论的。

4.生命周期

SqlSessionFactoryBuilder

  1. 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
  2. 局部变量

SqlSessionFactory

  1. SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  2. SqlSessionFactory 的最佳作用域是应用作用域

SqlSession

  1. 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  2. 为了确保每次都能执行关闭操作,你应该把这个关闭操作

5.resultMap

  1. 当数据库和pojo的类型不一样时,我们可以使用别名来进行操作

  2. 使用结果集来映射

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

在学习了上面的知识后,你会发现上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。 虽然上面的例子不用显式配置 ResultMap。 但为了讲解,我们来看看如果在刚刚的示例中,显式使用外部的 resultMap 会怎样,这也是解决列名不匹配的另外一种方式。

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

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

<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

世界要是总是这么简单就行了

对于复杂的

6.日志工厂

日志工程的配置,注意name不能变,后面的value都是固定的

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

可选的值有:

SLF4J

LOG4J

LOG4J2

JDK_LOGGING

COMMONS_LOGGING

STDOUT_LOGGING(直接设置就行了)

NO_LOGGING

或者是实现了 org.apache.ibatis.logging.Log 接口,且构造方法以字符串为参数的类完全限定名。

关于 log4j配置

1.导包

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2.在CLASSPATH下建立log4j.properties

配置内容参考

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/xueBatis.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3.将log4j实现

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

4.简单的使用

切记导

import org.apache.log4j.Logger;

这个包 声明一个变量

//加载一个日志对象
static Logger logger = Logger.getLogger(UserDaoTest.class);
    @Test
    public void LogTest() {
        //日志工程的测试实现
        logger.info("info:进入了级别");
        logger.debug("debug");
        logger.error("error");
    }

7.分页

1.使用limit分页 Map实现

select * from user limit 1,5

接口

List<User> getUserByLimit(Map<String,Integer> map);

实现

<resultMap id="UserMap" type="User">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="password" property="pwd"/>
</resultMap>
<select id="getUserByLimit" parameterType="map"  resultMap="UserMap">
    select *
    from user
    limit #{startIndex},#{endIndex}
</select>

测试

@Test
public void getUserByLimit() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("startIndex", 1);
        map.put("endIndex", 3);
        List<User> userByLimit = mapper.getUserByLimit(map);
        userByLimit.forEach(System.out::println);
    } finally {
        sqlSession.close();
    }
}

2.使用RowBounds(老东西)

接口

List<User> getUserByRowBounds();

实现

select id="getUserByRowBounds" resultMap="UserMap">
    select *
    from user
</select>

测试

@Test
public void getUserByRowBounds() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        //通过java代码
        //RowBounds
        RowBounds rowBounds = new RowBounds(1, 1);
        List<User> userByLimit = sqlSession.selectList("com.xue.dao.UserMapper.getUserByRowBounds",null,rowBounds);
        userByLimit.forEach(System.out::println);
    } finally {
        sqlSession.close();
    }
}

3.分页插件*

MyBatis 分页插件 PageHelper

8.注解开发

面向接口编程

面向接口编程 可以降低耦合度

选择

  @Select("select * from user")
    List<User> getUserListByAn();

带参数的

	@Select("select * from User where name =#{name}")
    List<User> getUserListByName(@Param("name") String name);

@Param()注解 **

  • 基本的参数要加上
  • 引用不用加
  • 如果有一个可以 忽略 但是建议加

9.Lombok(不建议使用)

在maven里添加

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor

10.多对一

1.嵌套查询

<select id="getStudentAndTeacher" resultMap="StudentJoinTeacher">
    select *
    from student
</select>

<resultMap id="StudentJoinTeacher" type="com.xue.pojo.Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher" javaType="Teacher" select="com.xue.dao.TeacherMapper.getTeacher" column="tid"/>
</resultMap>

2.Join查询

<resultMap id="StudentJoinTeacher" type="com.xue.pojo.Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher" javaType="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
    </association>
</resultMap>

<select id="getStudentAndTeacher" resultMap="StudentJoinTeacher">
    select *
    from student
             join teacher t on t.id = student.tid
</select>

11 一对多 (集合)

<resultMap id="TeacherStudent2" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="students" javaType="ArrayList" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sid"/>
    </collection>

</resultMap>
<select id="getTeacherAndStudent" resultMap="TeacherStudent2">
    select teacher.id   as tid,
           teacher.name as tname,
           s.id         as sid,
           s.name       as snaem,
           s.tid        as sstid
    from teacher
             join student s on teacher.id = s.tid
    where tid = #{id}
</select>

Mysql 引擎

InnoDB底层引擎

索引

索引优化

12 动态SQL

动态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 "浏览量"
)

pojo

@Data
public class Blog {
    private int id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

IF

<select id="queryBlog" resultType="Blog" parameterType="map">
    select *
    from blog
    <where>
        <if test="{title != null}">
            and title=#{title}
        </if>
        <if test="{title != null}">
            and title=#{title}
        </if>
    </where>
</select>

TEST

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

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap<String, Object> map = new HashMap<>();
    //map.put("title", "xx");

    List<Blog> blogs = mapper.queryBlog(map);
    blogs.forEach(System.out::println);

}

完美的复用了Map

choose

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。

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

SET

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

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

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

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

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

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

来看看与 set 元素等价的自定义 trim 元素吧:

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

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

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,以便你能充分利用已经创建的映射配置。

13 缓存

Redis

Memcache

nginx

主从复制

Mybatis 使用到了两种缓存:本地缓存(local cache)和二级缓存(second level cache)。

每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询结果都会被保存在本地缓存中,所以,当再次执行参数相同的相同查询时,就不需要实际查询数据库了。本地缓存将会在做出修改、事务提交或回滚,以及关闭 session 时清空。

默认情况下,本地缓存数据的生命周期等同于整个 session 的周期。由于缓存会被用来解决循环引用问题和加快重复嵌套查询的速度,所以无法将其完全禁用。但是你可以通过设置 localCacheScope=STATEMENT 来只在语句执行时使用缓存。

注意,如果 localCacheScope 被设置为 SESSION,对于某个对象,MyBatis 将返回在本地缓存中唯一对象的引用。对返回的对象(例如 list)做出的任何修改将会影响本地缓存的内容,进而将会影响到在本次 session 中从缓存返回的值。因此,不要对 MyBatis 所返回的对象作出更改,以防后患。

一级缓存

一级缓存也叫本地缓存,MyBatis 的一级缓存是在会话(SqlSession)层面进行缓存的。MyBatis 的一级缓存是默认开启的,不需要任何的配置。会话(SqlSession)层面进行缓存的

你可以随时调用以下方法来清空本地缓存:

void clearCache()
确保 SqlSession 被关闭
void close()

缓存失效情况:

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

二级缓存

二级缓存是用来解决一级缓存不能跨会话共享的问题的,范围是namespace 级别的,可以被多个SqlSession 共享(只要是同一个接口里面的相同方法,都可以共享),生命周期和应用同步。如果你的MyBatis使用了二级缓存,并且你的Mapper和select语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存,即MyBatis查询数据的顺序是:二级缓存 —> 一级缓存 —> 数据库。

第一步:配置 mybatis.configuration.cache-enabled=true,只要没有显式地设置cacheEnabled=false,都会用CachingExecutor 装饰基本的执行器。

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

第二步:在Mapper.xml 中配置标签:

<cache 
size="1024"
eviction="LRU"
flushInterval="120000"
readOnly="false"/>

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

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

默认的清除策略是 LRU。

缓存的原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bp8INice-1620752631557)(assets/1383365-20190628180149776-546074458.png)]

自定义缓存 ehcache

1.导入Maven

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

顺序是:二级缓存 —> 一级缓存 —> 数据库。

第一步:配置 mybatis.configuration.cache-enabled=true,只要没有显式地设置cacheEnabled=false,都会用CachingExecutor 装饰基本的执行器。

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

第二步:在Mapper.xml 中配置标签:

<cache 
size="1024"
eviction="LRU"
flushInterval="120000"
readOnly="false"/>

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

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

默认的清除策略是 LRU。

缓存的原理

[外链图片转存中…(img-Bp8INice-1620752631557)]

自定义缓存 ehcache

1.导入Maven

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值