码迷,mamicode.com
首页 > 其他好文 > 详细

28Mybatis_查询缓存-二级缓存-二级缓存测试-

时间:2016-08-22 20:10:54      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

二级缓存原理:

技术分享

 

首先开启mybatis的二级缓存。

 

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

 

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

 

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

 

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

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

每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

 

 

 

准备工作:

 开启二级缓存

 

mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。

 

在核心配置文件SqlMapConfig.xml中加入

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

 

 

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

 

 

 

技术分享

 

在UserMapper.xml中开启二缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)。

技术分享

 

 

测试:

 

第一步:在ordersMapperCustom.xml中开启二级缓存:

<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapperCustom">
  <cache></cache>

 

 

 

 

第二步:编写pojo类(要实现Serializable)必须要实现的:

为什么要实现Serializable接口呢:

为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一样在内存。

package cn.itcast.mybatis.po;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

public class User implements Serializable {
private int id;//对应数据库中主键
private String username;//对应数据库中用户的名称
private Date birthday;//对应数据库中的生日
private String sex;//性别
private String address;//地址
//一个用户对应多个订单表
private List<Orders> ordersList;
public List<Orders> getOrdersList() {
    return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
    this.ordersList = ordersList;
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public Date getBirthday() {
    return birthday;
}
public void setBirthday(Date birthday) {
    this.birthday = birthday;
}
public String getSex() {
    return sex;
}
public void setSex(String sex) {
    this.sex = sex;
}
public String getAddress() {
    return address;
}
public void setAddress(String address) {
    this.address = address;
}

}

 

 

第三步;编写测试代码:

 

package cn.itcast.mybatis.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

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 org.junit.Before;
import org.junit.Test;

import cn.itcast.mybatis.mapper.OrdersMapperCustom;
import cn.itcast.mybatis.mapper.userMapper;
import cn.itcast.mybatis.po.Orders;
import cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;

public class Mybatis_mappertest {
    
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setup() throws IOException
    {   String resource="SqlMapConfig.xml";
        InputStream inputStream= Resources.getResourceAsStream(resource);
        //主要是生成SqlsessionFactory。
        this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void testMaper()
    {
        SqlSession sqlSession1=null;
        SqlSession sqlSession2=null;
        sqlSession1=sqlSessionFactory.openSession();
        sqlSession2=sqlSessionFactory.openSession();
        //生成代理类
        OrdersMapperCustom orderMapper=sqlSession1.getMapper(OrdersMapperCustom.class);

         OrdersMapperCustom orderMapper2=sqlSession2.getMapper(OrdersMapperCustom.class);



User user
=orderMapper.finduserByid(1); //这个close必须要加,不然缓存存不进去。 sqlSession1.close(); User user2=orderMapper2.finduserByid(1); sqlSession2.close(); } }

 

运行结果:DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE ID=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5bae4145]
DEBUG [main] - Returned connection 1538146629 to pool.
DEBUG [main] - Cache Hit Ratio [cn.itcast.mybatis.mapper.OrdersMapperCustom]: 0.5

 

 

发现只有一条select语句,说明在执行第二条 User user2=orderMapper2.finduserByid(1)时,二级缓存发挥了作用。

 

 

我们注意到:

     

 //生成两个sqlsession。因为二级缓,多个sqlSession可以共享一个UserMapper的二级缓存区域。UserMapper有一个二级缓存区域(按namespace分)      
SqlSession sqlSession1=null; SqlSession sqlSession2=null; sqlSession1=sqlSessionFactory.openSession(); sqlSession2=sqlSessionFactory.openSession(); //生成代理类 OrdersMapperCustom orderMapper=sqlSession1.getMapper(OrdersMapperCustom.class); OrdersMapperCustom orderMapper2=sqlSession2.getMapper(OrdersMapperCustom.class); User user=orderMapper.finduserByid(1); User user2=orderMapper2.finduserByid(1);

 

这里的orderMapper,orderMapper2是不同的sqlSession生成的。但是没关系,二级缓存的作用范围是1.跨sqlSession.  2.

每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

 

 

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------

 

清空缓存的操作:

// 二级缓存测试
    @Test
    public void testCache2() throws Exception {
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();
        // 创建代理对象
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        // 第一次发起请求,查询id为1的用户
        User user1 = userMapper1.findUserById(1);
        System.out.println(user1);
        
        //这里执行关闭操作,将sqlsession中的数据写到二级缓存区域
        sqlSession1.close();
        
        
        //使用sqlSession3执行commit()操作
        UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
        User user  = userMapper3.findUserById(1);
        user.setUsername("张明明");
        userMapper3.updateUser(user);
        //执行提交,清空UserMapper下边的二级缓存
        sqlSession3.commit();
        sqlSession3.close();
        
        

        UserMapper userMapper2 =    sqlSession2.getMapper(UserMapper.class);
        // 第二次发起请求,查询id为1的用户,因为前面的操作清除了缓存,所以这里的操作会重新从数据库中去查询。
        User user2 = userMapper2.findUserById(1);
        System.out.println(user2);

        sqlSession2.close();

    }

 

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------

有没有这样的一种情况,一个mapper.xml中,有些sql语句是要缓存功能的,但是有些sql语句我不想他具有缓存功能,需要每次都从数据库中得到数据?可以

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。

 

这样的话这个mapper.xml中别的sql语句具有二级缓存的功能,这句sql语句就没有了缓存功能,每次读取数据时都要从数据库中去读数据。

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

  刷新缓存(就是清空缓存)

在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。

 

 设置statement配置中的flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。

如下:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

 

总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。

 

28Mybatis_查询缓存-二级缓存-二级缓存测试-

标签:

原文地址:http://www.cnblogs.com/shenxiaoquan/p/5796733.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!