[华为云在线课程][MyBatis入门][五][MyBatis缓存][学习笔记]

举报
John2021 发表于 2022/10/30 14:10:47 2022/10/30
【摘要】 1.MyBatis一级缓存MyBatis一级缓存的作用域是同一个SqlSession,在同一个SqlSession中两次执行相同的sql语句,第一次执行完毕后将数据库中查询到的数据写到缓存(内存)中,第二次会从缓存中获取数据将不再从数据库查询,从而提高效率。当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了。MyBatis默认开启一级缓存。package org...

1.MyBatis一级缓存

MyBatis一级缓存的作用域是同一个SqlSession,在同一个SqlSession中两次执行相同的sql语句,第一次执行完毕后将数据库中查询到的数据写到缓存(内存)中,第二次会从缓存中获取数据将不再从数据库查询,从而提高效率。
当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了。MyBatis默认开启一级缓存。

package org.example.mybatis04.model;

public class User {
    private Integer id;
    private String username;
    private String address;

    public User() {
    }

    public User(Integer id, String username, String address) {
        this.id = id;
        this.username = username;
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
package org.example.mybatis04.mapper;

import org.example.mybatis04.model.User;

public interface UserMapper {
    User getUserById(Integer id);
}
<mappers>
    <mapper resource="org/example/mybatis04/mapper/UserMapper.xml"/>
</mappers>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/schema/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis04.mapper.UserMapper">
    <select id="getUserById" resultType="org.example.mybatis04.model.User">
        select * from user where id=#{id};
    </select>
</mapper>
package org.example.mybatis04;

import org.apache.ibatis.session.SqlSession;
import org.example.mybatis04.mapper.UserMapper;
import org.example.mybatis04.model.User;
import org.example.mybatis04.utils.SqlSessionFactoryUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class UserMapperTest {
    private SqlSession sqlSession;
    @Before
    public void before() {
        sqlSession= SqlSessionFactoryUtils.getInstance().openSession();
    }

    @Test
    public void getUserById() {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User userById = userMapper.getUserById(1);
        System.out.println(userById);
        /*
          <==      Total: 1
          User{id=1, username='aaaa', address='beijing'}
        * */
    }

    @After
    public void after() {
        sqlSession.close();
    } 
}
[DEBUG] 2022-07-11 06:19:58,998[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:137)
Opening JDBC Connection
[DEBUG] 2022-07-11 06:19:59,438[yyyy-MM-dd] method:org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:434)
Created connection 1491860739.
[DEBUG] 2022-07-11 06:19:59,438[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:101)
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 06:19:59,438[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from user where id=?;
[DEBUG] 2022-07-11 06:19:59,463[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: 1(Integer)
[DEBUG] 2022-07-11 06:19:59,494[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
User{id=1, username='aaaa', address='beijing'}
[DEBUG] 2022-07-11 06:19:59,503[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.resetAutoCommit(JdbcTransaction.java:123)
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 06:19:59,503[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.close(JdbcTransaction.java:91)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
@Test
public void getUserById() {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User userById = userMapper.getUserById(1);
    System.out.println("userById = " + userById);
    System.out.println("################################");
    User userById1 = userMapper.getUserById(2);
    System.out.println("userById1 = " + userById1);
}
[DEBUG] 2022-07-11 07:16:11,537[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:137)
Opening JDBC Connection
[DEBUG] 2022-07-11 07:16:11,952[yyyy-MM-dd] method:org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:434)
Created connection 1491860739.
[DEBUG] 2022-07-11 07:16:11,952[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:101)
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 07:16:11,957[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from user where id=?;
[DEBUG] 2022-07-11 07:16:11,982[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: 1(Integer)
[DEBUG] 2022-07-11 07:16:12,002[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
userById = User{id=1, username='aaaa', address='beijing'}
################################
[DEBUG] 2022-07-11 07:16:12,012[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from user where id=?;
[DEBUG] 2022-07-11 07:16:12,012[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: 2(Integer)
[DEBUG] 2022-07-11 07:16:12,012[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
userById1 = User{id=2, username='bb', address='shanghai'}
[DEBUG] 2022-07-11 07:16:12,017[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.resetAutoCommit(JdbcTransaction.java:123)
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 07:16:12,017[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.close(JdbcTransaction.java:91)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
@Test
public void getUserById() {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User userById = userMapper.getUserById(1);
    System.out.println("userById = " + userById);
    System.out.println("################################");
    User userById1 = userMapper.getUserById(1);
    System.out.println("userById1 = " + userById1);
}
[DEBUG] 2022-07-11 07:18:40,977[yyyy-MM-dd] method:org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:434)
Created connection 1491860739.
[DEBUG] 2022-07-11 07:18:40,977[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:101)
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 07:18:40,977[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from user where id=?;
[DEBUG] 2022-07-11 07:18:41,007[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: 1(Integer)
[DEBUG] 2022-07-11 07:18:41,042[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
userById = User{id=1, username='aaaa', address='beijing'}
################################
userById1 = User{id=1, username='aaaa', address='beijing'}
[DEBUG] 2022-07-11 07:18:41,057[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.resetAutoCommit(JdbcTransaction.java:123)
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]
[DEBUG] 2022-07-11 07:18:41,057[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.close(JdbcTransaction.java:91)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@58ebfd03]

多次查询,只执行一次SQL。但要注意,如果开启了一个新的SqlSession,则新的SqlSession无法使用之前的缓存,必须是同一个SqlSession中,缓存才有效。

2.MyBatis二级缓存

MyBatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的SqlSession两次执行相同namespace下的SQL语句且SQL中传递参数也相同即最终执行相同的SQL语句,第一次执行完毕将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提供查询效率。MyBatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。

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

然后在UserMapper.xml文件中开启缓存

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/schema/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis04.mapper.UserMapper">
    <cache/>
    <select id="getUserById" resultType="org.example.mybatis04.model.User" useCache="true">
        select * from user where id=#{id};
    </select>
</mapper>

开启了二级缓存后,还需要将要缓存的实体类实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储可能在内存或者硬盘中,如果我们再取出这个缓存的话就需要反序列化。

package org.example.mybatis04.model;

import java.io.Serializable;

public class User implements Serializable{
    private Integer id;
    private String username;
    private String address;
}

如果没有在实体类中实现Serializable接口的话就会报出以下错误:

org.apache.ibatis.cache.CacheException: Error serializing object.  Cause: java.io.NotSerializableException: org.example.mybatis04.model.User

接下来我们测试二级缓存是否和SqlSession有关

@Test
public void getUserById2() {
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
    //第一次查询有sql语句,并将查询的结果放入缓存中
    User user1 = userMapper1.getUserById(1);
    System.out.println(user1);
    //第一次查询后关闭SqlSession,SqlSession关闭后就会清除一级缓存
    sqlSession1.close();
    //SqlSession关闭后执行第二次查询,发现这次依然没有sql语句
    User user2 = userMapper2.getUserById(1);
    System.out.println(user2);
    sqlSession2.close();
}

输出结果:

[DEBUG] 2022-07-12 05:43:23,742[yyyy-MM-dd] method:org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:60)
Cache Hit Ratio [org.example.mybatis04.mapper.UserMapper]: 0.0
[DEBUG] 2022-07-12 05:43:23,745[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:137)
Opening JDBC Connection
[DEBUG] 2022-07-12 05:43:24,201[yyyy-MM-dd] method:org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:434)
Created connection 664091267.
[DEBUG] 2022-07-12 05:43:24,201[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:101)
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27953a83]
[DEBUG] 2022-07-12 05:43:24,204[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==>  Preparing: select * from user where id=?;
[DEBUG] 2022-07-12 05:43:24,230[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
==> Parameters: 1(Integer)
[DEBUG] 2022-07-12 05:43:24,257[yyyy-MM-dd] method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137)
<==      Total: 1
User{id=1, username='aaaa', address='beijing'}
[DEBUG] 2022-07-12 05:43:24,270[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.resetAutoCommit(JdbcTransaction.java:123)
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27953a83]
[DEBUG] 2022-07-12 05:43:24,270[yyyy-MM-dd] method:org.apache.ibatis.transaction.jdbc.JdbcTransaction.close(JdbcTransaction.java:91)
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27953a83]
[DEBUG] 2022-07-12 05:43:24,270[yyyy-MM-dd] method:org.apache.ibatis.datasource.pooled.PooledDataSource.pushConnection(PooledDataSource.java:391)
Returned connection 664091267 to pool.
[WARN ] 2022-07-12 05:43:24,271[yyyy-MM-dd] method:org.apache.ibatis.io.SerialFilterChecker.check(SerialFilterChecker.java:45)
As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
[DEBUG] 2022-07-12 05:43:24,273[yyyy-MM-dd] method:org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:60)
Cache Hit Ratio [org.example.mybatis04.mapper.UserMapper]: 0.5
User{id=1, username='aaaa', address='beijing'}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。