缓存(mybatis)

来源:互联网 发布:dts音效软件 编辑:程序博客网 时间:2024/04/30 12:44

1.什么是查询缓存:

mybaitis也提供了查询缓存,用于减少数据库访问次数,提高了数据库的性能而存在的一种机制。有一级、二级缓存。



一级缓存:操作数据库时,会操作会话SqlSession对象,在会话对象中有个内存(数据结构HashMap),用于存储缓存数据。

不同的SqlSession他们之间的缓存数据区域是互补影响的。

二级缓存:Mapper级别的缓存,多个SqlSession去操作同一个Mapper的SQL语句。多个SQLSession操作数据库所得到数据会存储在二级缓存区域,可以共用二级缓存,二级缓存是跨SqlSession的。




一级缓存:

第一次发起查询用户id为1的用户信息,先去缓存中找是否有id为1的用户信息,如果没有,会到数据库中查询出来,并存储到一级缓存中。

如果在第一次查询和第二次查询中间有操作事务操作,一级缓存里的数据被自动清空。如果不清除,第二次查询到的还是第一次的数据。为了让缓存中永远存储最新的查询数据,也就是为了避免脏数据。

第二次发起查询用户id为1的用户信息,先去缓存中找是否有id为1的用户信息,查到有,会直接返回出来。


缓存的作用:如果缓存中有需要查询的数据,就不需要去数据库中查找,减少对数据库的访问。


一级缓存测试:

mybaitis和hibernate一样默认开启一级缓存,无须配置。

按照上面一级缓存原理去进行测试。


/** * 首先说明一点,一级缓存就是SqlSession级别的缓存 * 一级缓存工作原理:第一次查询的时候,会先去sqlSessionX的缓存查询数据是否存在, * 不存在去数据库查,查到放入sqlSessionX缓存。第二次查同一个ID的数据时,还是先去sqlSessionX缓存找,找到就返回出来。 */public static void testcache1(){SqlSession sqlSessionX =  MybaitisUtil.getSQLSession();        UserMapper userMapper = sqlSessionX.getMapper(UserMapper.class);        User user1 = userMapper.selectByuid(1);        System.out.println(user1);User user2 = userMapper.selectByuid(2);//其他IDSystem.out.println(user2);User user3 = userMapper.selectByuid(1);System.out.println(user3);                Mybatis.close(sqlSessionX);//关闭之后,再次创建依然是先去session找,肯定没有,去数据库查找数据。 }

打印结果:


public static void testcache1(){    SqlSession sqlSessionX =  MybaitisUtil.getSQLSession();    UserMapper userMapper = sqlSessionX.getMapper(UserMapper.class);    User user1 = userMapper.selectByuid(1);    System.out.println(user1);        //进行事务操作    user1.setUsername("zhangsan");    userMapper.updateuser(user1);    sqlSessionX.commit(); //提交事务后,在缓存中的数据会被自动清除。所以,下面的查询会再次去数据库查询。        User user2 = userMapper.selectByuid(1);    System.out.println(user2);            Mybatis.close(sqlSessionX);}
打印结果:



在spring和mybaitis的开发中,事务控制在Service层,一个Service包括了多个mapper的调用,

 Service{

 //开始执行时,开启事务,创建SqlSession对象,

//第一次调用mapper.findbyId(1);

//第二次调用mapper.findbyId(1);//从一级缓存读取,

//方法结束,SqlSession关闭。


}


如果是执行多次service调用查询相同用户信息,不会搞这个一级缓存,因为SqlSession方法结束,SqlSession就关闭,一级缓存当然就清空!所以,需要使用二级缓存(mapper级别的缓存)。





SqlSession1去查询id为1的用户信息,查询到的用户信息会将查询数据存储到二级缓存。

如果SqlSession3去执行相同mapper下的sql,执行commit提交,清空该mapper下的二级缓存区域的数据。

SqlSession2去查询id为2的用户信息,去缓存中查找,是否存在数据,如果存在直接从二级缓存中取出数据。

二级缓存和一级缓存的区别,二级缓存的范围大,多个sqlsession可以共享一个UserMapper的二级缓存区域。

UserMapper有一个二级缓存区域(按照namespace分)其他也有自己的缓存区域。

每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,那么查询到的数据就会放在同一个二级缓存中。

mybatis的二级缓存的准备工作:

1、mybatis-config.xml 添加:<setting name="cacheEnabled" value="true"/>

2、Usermapper.xml 添加:<cache/>

3、pojo需要序列化。

测试代码:

/**     * 二级缓存测试:     * 二级缓存是mapper级别的缓存,创建三个usermapper对象,     * 第一个usermapper去二级缓存查看数据,没有找到去数据库查找,将数据存储在二级缓存内,第二个usermapper首先会去二级缓存,找到将值返回。     * 如果中间有事务操作,会清空缓存。     */public static void testcache2(){SqlSession sqlSession1 = MybaitisUtil.getSQLSession();SqlSession sqlSession2 = MybaitisUtil.getSQLSession();SqlSession sqlSession3 = MybaitisUtil.getSQLSession();SqlSession sqlSession4 = MybaitisUtil.getSQLSession();        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);        System.out.println(userMapper1.selectByuid(1));        sqlSession1.close();            UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);        System.out.println(userMapper2.selectByuid(1));        sqlSession2.close();        //事务操作    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);    User user = userMapper3.selectByuid(1);    user.setUsername("李四");    userMapper3.updateuser(user);    sqlSession3.commit();//整个UsernMapper缓存被清空    sqlSession3.close();        UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);    System.out.println(userMapper4.selectByuid(1));    sqlSession4.close();    }
打印结果:




每次查询如果需要最新数据,需要禁用二级缓存:在mapper.xml上可以添加useCache="false"。

  <!--查询需要: 输入的映射参数类型parameterType=int,输出映射参数类型resultType=User 是最终查询结果的数据类型-->  <select id="selectByuid" parameterType="int" resultType="user" useCache="false"> <!-- useCache="false" 禁用二级缓存 -->     select * from user where id=#{id}    </select>

public static void testcache2(){SqlSession sqlSession1 = MybaitisUtil.getSQLSession();SqlSession sqlSession2 = MybaitisUtil.getSQLSession();SqlSession sqlSession3 = MybaitisUtil.getSQLSession();SqlSession sqlSession4 = MybaitisUtil.getSQLSession();    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);    System.out.println(userMapper1.selectByuid(1));    sqlSession1.close();        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);    System.out.println(userMapper2.selectByuid(1));    sqlSession2.close();        //事务操作//    UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);//    User user = userMapper3.selectByuid(1);//    user.setUsername("李四");//    userMapper3.updateuser(user);//    sqlSession3.commit();//    sqlSession3.close();        UserMapper userMapper4 = sqlSession4.getMapper(UserMapper.class);    System.out.println(userMapper4.selectByuid(1));    sqlSession4.close();    }

打印结果:




2.分布式缓存:

如图:现在又服务器1和服务器2。用户向服务器1请求数据查询,把缓存存储在服务器1,当用户请求到服务器2的时候,发现并没有缓存,这就是一个很尴尬的事情。

mybatis需要和其他框架整合,对缓存数据进行集中管理。





为了系统的性能提升,对缓存数据进行集中的管理,使用分布式缓存。


3.应用场景和局限性

对于访问多的查询请求且用户查询结果实时性不高,此时可以采用mybatis二级缓存技术降低数据库的访问量,业务场景:耗时较高的统计分析Sql,电话账单查询sql等等,

通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushinterval,比如30分钟一小时24小时。

mybaitis二级缓存粒度的数据级别缓存实现不好,比如:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品,此时就无法满足刷新当前商品信息,而不刷新其他商品,因为mybatis的二级缓存是以mapper位单位的,解决这种问题需要在业务层根据需求对数据库有针对性缓存。



0 0
原创粉丝点击