Mybatis入门笔记(11)——Mybatis的缓存
Mybatis的缓存
缓存基本概念
缓存是存在于内存中的临时数据
为什么用缓存?减少和数据库的交互次数,提高执行效率。
什么地方用缓存?
条件 | 情况 |
---|---|
适用于缓存 | 经常查询并且不经常改变的,数据的正确与否对最终结果影响不大的 |
不适用于缓存 | 经常改变的数据,数据的正确性与否对最终结果影响很大的,比如:商品的库存,银行的汇率,股市的牌价等。 |
一级缓存
一级缓存指的是Mybatis中SqlSession对象的缓存。当我们执行查询后,查询的结构会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,Mybatis会先去SQLSession中查询是否有,有的话直接拿出来用。当SQLSession对象消失后(被flush或close),Mybatis的一级缓存也就消失了。
下面举例说明:
-
编写用户持久层Dao接口;
public interface IUserDao { // 根据ID查询用户 User findUserById(Integer id); }
-
编写持久层映射文件;
<?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.ben.dao.IUserDao"> <!-- 配置 查询结果的列名和实体类的属性名的对应关系 --> <resultMap id="userMap" type="uSer"> <!-- 主键字段的对应 --> <id property="userId" column="id"></id> <!--非主键字段的对应--> <result property="userName" column="username"></result> <result property="userAddress" column="address"></result> <result property="userSex" column="sex"></result> <result property="userBirthday" column="birthday"></result> </resultMap> <!-- 查询所有 --> <select id="findUserById" resultMap="userMap"> select * from user where id = #{v}; </select> </mapper>
-
编写测试方法
public class MybatisTest { private SqlSessionFactory factory; private IUserDao userdao; private InputStream in; private SqlSession session; // 作用:在测试方法前执行这个方法 @Before public void setUp() throws Exception { //1.读取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建SqlSessionFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //3.创建SqlSession工厂对象 factory = builder.build(in); //4.使用工厂生产SqlSession对象 session = factory.openSession(); //5.创建Dao接口的代理对象 userdao = session.getMapper(IUserDao.class); } @After//在测试方法执行完成之后执行 public void destroy() throws IOException { session.close(); in.close(); } // 根据用户ID查找用户 @Test public void testFindUserById(){ User user1 = userdao.findUserById(41); System.out.println(user1); session.close(); //再次生产SqlSession对象 session = factory.openSession(); userdao = session.getMapper(IUserDao.class); User user2 = userdao.findUserById(41); System.out.println(user2); System.out.println(user1 == user2); } }
当执行sqlSession.close()后,再次获取sqlSession并查询id=41的User对象时,又重新执行了sql语句,从数据
库进行了查询操作。 结果发现,两次拿到的数据不一样。
此外还可以通过 session.clearCache()
清空一级缓存。
// 根据用户ID查找用户
@Test
public void testFindUserById() {
User user1 = userdao.findUserById(41);
System.out.println(user1);
// session.close();
session.clearCache();
//再次生产SqlSession对象
session = factory.openSession();
userdao = session.getMapper(IUserDao.class);
User user2 = userdao.findUserById(41);
System.out.println(user2);
System.out.println(user1 == user2);
}
二级缓存
它指的是Mybatis中SQLSessionFactory对象的缓存,由同一个SQLSessionFactory对象创建的SqlSession共享其缓存。
使用步骤:
-
让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
<!-- 配置缓存--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
-
让当前的映射文件支持二级缓存(在IUserDao.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"> <mapper namespace="com.ben.dao.IUserDao"> <cache/> <!-- 配置 查询结果的列名和实体类的属性名的对应关系 --> <resultMap id="userMap" type="uSer"> <!-- 主键字段的对应 --> <id property="userId" column="id"></id> <!--非主键字段的对应--> <result property="userName" column="username"></result> <result property="userAddress" column="address"></result> <result property="userSex" column="sex"></result> <result property="userBirthday" column="birthday"></result> </resultMap> <!-- 查询所有 --> <select id="findUserById" resultMap="userMap" useCache="true"> select * from user where id = #{v}; </select> </mapper>
-
让当前的操作支持二级缓存(在select标签中配置) useCache="true"
编写测试类
@Test
public void testSecondCache() {
SqlSession session = factory.openSession();
IUserDao dao1 = session.getMapper(IUserDao.class);
User user1 = dao1.findUserById(41);
System.out.println(user1);
//一级缓存消失
session.close();
// session.clearCache();
//再次生产SqlSession对象
SqlSession session2 = factory.openSession();
IUserDao dao2 = session2.getMapper(IUserDao.class);
User user2 = dao2.findUserById(41);
System.out.println(user2);
session.close();
System.out.println(user1 == user2);
}
经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二
次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。 第二次直接从二级缓存中拿到的数据。
二级缓存图解:二级缓存存放的内容是数据,而不是对象。