缓存:
- 存在内存中的临时数据。
- 将用户经常查询的数据放在缓存中,再次查询时无需访问磁盘,提高效率。解决高并发问题。
- 可以减少IO。
- 经常查询且不常改变的数据适合使用缓存。
(注意:读数据才走缓存)
Mybatis缓存
官方文档:
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
-
Mybatis有着非常强大的缓存特性,可以非常方便地定制和配置缓存。
-
Mybatis中定义了两级缓存:一级缓存和二级缓存
一级缓存:默认情况下一级。SqlSession级别,也称为本地缓存。
二级缓存: 需要手动开启和配置,namespace级别 -
自定义缓存:Mybatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存。
Cache接口实现类
示例
获得SqlSession的工具类,openSession为true时自动提交事务
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
SqlSession sqlSession = sqlSessionFactory.openSession(true); //自动提交事务
return sqlSession;
}
}
UserMapper接口
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
//根据id查询用户
User queryUserById(@Param("id") int id);
//修改用户
int updateUser(User user);
}
xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jacob.dao.UserMapper">
<select id="queryUserById" parameterType="_int" resultType="user">
select * from user where user = #{id}
</select>
<update id="updateUser" parameterType="user">
update user set pwd=#{pwd} where user=#{user}
</update>
</mapper>
测试类MyTest
- 一级缓存
import com.jacob.dao.UserMapper;
import com.jacob.pojo.User;
import com.jacob.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MyTest {
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
User user1 = mapper.queryUserById(1); //只查询一次
System.out.println(user == user1); //从缓存拿到user1, true
sqlSession1.close();
}
}
增删改可能会改变原来数据, 所以会刷新缓存
public class MyTest {
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
mapper.updateUser(new User(4, "jj", "14")); //刷新了缓存
User user1 = mapper.queryUserById(1); //查询第二次
System.out.println(user == user1); //false
sqlSession1.close();
}
}
执行结果如下:
利用sqlSession.clearCache()清理缓存
public class MyTest {
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
sqlSession.clearCache(); //清理缓存
User user1 = mapper.queryUserById(1); //查询第二次
System.out.println(user == user1); //false
sqlSession1.close();
}
}
-
二级缓存
namespace级别
工作机制:- 一个会话查询一条数据,数据会存放在当前会话的一级缓存中
- 若当前会话关闭,这个会话的一级缓存消失, 开启二级缓存后,一级缓存的数据保存至二级缓存
- 新的会话可在二级缓存获取数据
在Mapper中开启
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jacob.dao.UserMapper">
<cache readOnly="true"/>
<select id="queryUserById" parameterType="_int" resultType="user" useCache="true">
select * from user where user = #{id}
</select>
<update id="updateUser" parameterType="user">
update user set pwd=#{pwd} where user=#{user}
</update>
</mapper>
public class MyTest {
@Test
public void test() {
//两个 sqlSession
SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession1 = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
sqlSession.close(); //sqlSession关闭了数据进入二级缓存
User user1 = mapper1.queryUserById(1);
System.out.println(user == user1); //从缓存拿到user1, true
sqlSession1.close();
}
}
若sqlSession 后关闭,查询了两次
public class MyTest {
@Test
public void test() {
//两个 sqlSession
SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession1 = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
User user1 = mapper1.queryUserById(1);
System.out.println(user == user1); //false, sqlSession未关闭,二级缓存中没有数据,不同sqlSession,一级缓存不同
sqlSession.close();
sqlSession1.close();
}
}
查询了两次
- 缓存原理(来自狂神说Java)