Spring Boot + Mybatis + Ehcache 二级缓存实例

来源:互联网 发布:官方刷机软件 编辑:程序博客网 时间:2024/06/10 00:02

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

下面是使用Ehcache来作为Mybatis二级缓存的实例:

application.properties开启mybatis中二级缓存

mybatis.configuration.cache-enabled=true

默认二级缓存是开启的

server.port=80# 数据源配置spring.datasource.url=jdbc:mysql://localhost:3306/ssb_testspring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.username=rootspring.datasource.password=root#连接池配置#spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource#mybatis#entity扫描的包名mybatis.type-aliases-package=com.xiaolyuh.domain.model#Mapper.xml所在的位置mybatis.mapper-locations=classpath*:/mybaits/*Mapper.xml#开启MyBatis的二级缓存mybatis.configuration.cache-enabled=true#pagehelperpagehelper.helperDialect=mysqlpagehelper.reasonable=truepagehelper.supportMethodsArguments=truepagehelper.params=count=countSql#日志配置logging.level.com.xiaolyuh=debuglogging.level.org.springframework.web=debuglogging.level.org.springframework.transaction=debuglogging.level.org.mybatis=debugdebug=false

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><artifactId>spring-boot-student-mybatis-ehcache</artifactId><packaging>jar</packaging><name>spring-boot-student-mybatis-ehcache</name><description>Demo Mybatis ehcache for Spring Boot</description><parent><groupId>com.xiaolyuh</groupId><artifactId>spring-boot-student</artifactId><version>0.0.1-SNAPSHOT</version><relativePath /></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.0</version></dependency><!--pagehelper --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.1.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.31</version></dependency><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-ehcache</artifactId><version>1.0.0</version></dependency></dependencies></project>

Ehcache配置

在src\main\resources目录下创建ehcache.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?><ehcache>    <!--        http://www.cnblogs.com/lzy1991/p/5335249.html        http://www.cnblogs.com/little-fly/p/6251439.html        缓存配置           diskStore:指定数据在磁盘中的存储位置。           name:缓存名称。           defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略,以下属性是必须的:           maxElementsInMemory:缓存最大个数。           eternal:对象是否永久有效,一但设置了,timeout将不起作用。           timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。           timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。           overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。           diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。           maxElementsOnDisk:硬盘最大缓存个数。           diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.           diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。           memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。           clearOnFlush:内存数量最大时是否清除。    -->    <diskStore path="e:\ehcache" />    <defaultCache            maxElementsInMemory="10000"            eternal="false"            timeToIdleSeconds="120"            timeToLiveSeconds="120"            overflowToDisk="true"            maxElementsOnDisk="10000000"            diskPersistent="false"            diskExpiryThreadIntervalSeconds="120"            memoryStoreEvictionPolicy="LRU"    /></ehcache>

Mapper文件

<cache /> 添加这个节点会默认将该namespace下所有的的select语句缓存。如果不需要进行缓存,需要设置useCache="false"。

<select id="findByPage" resultMap="BaseResultMap" useCache="false">

完整的Mapper文件,如下:

<?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.xiaolyuh.domain.mapper.PersonMapper">    <!--mybatis ehcache缓存配置 -->    <!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->    <!--<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>-->    <!--根据需求调整缓存参数:-->    <cache type="org.mybatis.caches.ehcache.EhcacheCache">        <property name="timeToIdleSeconds" value="3600"/>        <property name="timeToLiveSeconds" value="3600"/>        <!-- 同ehcache参数maxElementsInMemory -->        <property name="maxEntriesLocalHeap" value="1000"/>        <!-- 同ehcache参数maxElementsOnDisk -->        <property name="maxEntriesLocalDisk" value="10000000"/>        <property name="memoryStoreEvictionPolicy" value="LRU"/>    </cache>    <resultMap id="BaseResultMap" type="com.xiaolyuh.domain.model.Person">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        <id column="id" property="id" jdbcType="BIGINT"/>        <result column="name" property="name" jdbcType="VARCHAR"/>        <result column="age" property="age" jdbcType="INTEGER"/>        <result column="address" property="address" jdbcType="VARCHAR"/>    </resultMap>    <sql id="Base_Column_List">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        id, name, age, address    </sql>    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        select        <include refid="Base_Column_List"/>        from person        where id = #{id,jdbcType=BIGINT}    </select>    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        delete from person        where id = #{id,jdbcType=BIGINT}    </delete>    <insert id="insert" parameterType="com.xiaolyuh.domain.model.Person">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        <selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER">            SELECT LAST_INSERT_ID()        </selectKey>        insert into person (name, age, address        )        values (#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{address,jdbcType=VARCHAR}        )    </insert>    <insert id="insertSelective" parameterType="com.xiaolyuh.domain.model.Person">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        <selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER">            SELECT LAST_INSERT_ID()        </selectKey>        insert into person        <trim prefix="(" suffix=")" suffixOverrides=",">            <if test="name != null">                name,            </if>            <if test="age != null">                age,            </if>            <if test="address != null">                address,            </if>        </trim>        <trim prefix="values (" suffix=")" suffixOverrides=",">            <if test="name != null">                #{name,jdbcType=VARCHAR},            </if>            <if test="age != null">                #{age,jdbcType=INTEGER},            </if>            <if test="address != null">                #{address,jdbcType=VARCHAR},            </if>        </trim>    </insert>    <update id="updateByPrimaryKeySelective" parameterType="com.xiaolyuh.domain.model.Person">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        update person        <set>            <if test="name != null">                name = #{name,jdbcType=VARCHAR},            </if>            <if test="age != null">                age = #{age,jdbcType=INTEGER},            </if>            <if test="address != null">                address = #{address,jdbcType=VARCHAR},            </if>        </set>        where id = #{id,jdbcType=BIGINT}    </update>    <update id="updateByPrimaryKey" parameterType="com.xiaolyuh.domain.model.Person">        <!--          WARNING - @mbggenerated          This element is automatically generated by MyBatis Generator, do not modify.        -->        update person        set name = #{name,jdbcType=VARCHAR},        age = #{age,jdbcType=INTEGER},        address = #{address,jdbcType=VARCHAR}        where id = #{id,jdbcType=BIGINT}    </update>    <!-- 对这个语句useCache="true"默认是true,可以不写 -->    <select id="findAll" resultMap="BaseResultMap" useCache="true">        select        <include refid="Base_Column_List"/>        from person    </select>    <!-- 对这个语句禁用二级缓存 -->    <select id="findByPage" resultMap="BaseResultMap" useCache="false">        select        <include refid="Base_Column_List"/>        from person    </select></mapper>

实体类

package com.xiaolyuh.domain.model;import java.io.Serializable;public class Person implements Serializable {    private Long id;    /**     * 名称     */    private String name;    /**     * 年龄     */    private Integer age;    /**     * 地址     */    private String address;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }}

Mapper-类

package com.xiaolyuh.domain.mapper;import com.github.pagehelper.Page;import com.xiaolyuh.domain.model.Person;import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper//声明成mybatis Dao层的Bean,也可以在配置类上使用@MapperScan("com.xiaolyuh.domain.mapper")注解声明public interface PersonMapper {    int deleteByPrimaryKey(Long id);    int insert(Person record);    int insertSelective(Person record);    Person selectByPrimaryKey(Long id);    int updateByPrimaryKeySelective(Person record);    int updateByPrimaryKey(Person record);    /**     * 获取所有数据     * @return     */    List<Person> findAll();    /**     * 分页查询数据     * @return     */    Page<Person> findByPage();}

Severice接口类

package com.xiaolyuh.service;import com.github.pagehelper.Page;import com.xiaolyuh.domain.model.Person;import java.util.List;/** * Created by yuhao.wang on 2017/6/19. */public interface PersonService {    List<Person> findAll();    /**     * 分页查询     * @param pageNo 页号     * @param pageSize 每页显示记录数     * @return     */    Page<Person> findByPage(int pageNo, int pageSize);    void insert(Person person);}

Severice实现类

package com.xiaolyuh.service.impl;import com.github.pagehelper.Page;import com.github.pagehelper.PageHelper;import com.xiaolyuh.domain.mapper.PersonMapper;import com.xiaolyuh.domain.model.Person;import com.xiaolyuh.service.PersonService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.List;/** * Created by yuhao.wang on 2017/6/19. */@Service@Transactional(readOnly = true)public class PersonServiceImpl implements PersonService {    @Autowired    private PersonMapper personMapper;    @Override    public List<Person> findAll() {        return personMapper.findAll();    }    @Override    public Page<Person> findByPage(int pageNo, int pageSize) {        PageHelper.startPage(pageNo, pageSize);        return personMapper.findByPage();    }    @Override    @Transactional    public void insert(Person person) {        personMapper.insert(person);    }}

测试类

package com.xiaolyuh;import com.github.pagehelper.Page;import com.xiaolyuh.domain.model.Person;import com.xiaolyuh.service.PersonService;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import com.alibaba.fastjson.JSON;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)@SpringBootTestpublic class PersonMapperTests {    private Logger logger = LoggerFactory.getLogger(PersonMapperTests.class);    @Autowired    private PersonService personService;    @Before    public void testInsert() {        Person person = new Person();        person.setName("测试");        person.setAddress("address");        person.setAge(10);        personService.insert(person);        Assert.assertNotNull(person.getId());        logger.debug(JSON.toJSONString(person));    }    @Test    public void testFindAll() {        List<Person> persons = personService.findAll();        Assert.assertNotNull(persons);        logger.debug(JSON.toJSONString(persons));    }    @Test    public void testFindByPage() {        Page<Person> persons = personService.findByPage(1, 2);        Assert.assertNotNull(persons);        logger.debug(persons.toString());        logger.debug(JSON.toJSONString(persons));    }    @Test    public void testCacheByPage() {        long begin = System.currentTimeMillis();        List<Person> persons = personService.findAll();        long ing = System.currentTimeMillis();        personService.findAll();        long end = System.currentTimeMillis();        logger.debug("第一次请求时间:" + (ing - begin) + "ms");        logger.debug("第二次请求时间:" + (end - ing) + "ms");        Assert.assertNotNull(persons);        logger.debug(persons.toString());        logger.debug(JSON.toJSONString(persons));    }}

执行测试类,打印日志信息

Cache Hit Ratio [com.xiaolyuh.domain.mapper.PersonMapper]: 0.52017-06-28 10:15:32.214 DEBUG 10472 --- [           main] org.mybatis.spring.SqlSessionUtils       : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f6c2763]2017-06-28 10:15:32.214 DEBUG 10472 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f6c2763]2017-06-28 10:15:32.214 DEBUG 10472 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f6c2763]2017-06-28 10:15:32.214 DEBUG 10472 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3f6c2763]2017-06-28 10:15:32.223 DEBUG 10472 --- [           main] com.xiaolyuh.PersonMapperTests           : 第一次请求时间:26ms2017-06-28 10:15:32.223 DEBUG 10472 --- [           main] com.xiaolyuh.PersonMapperTests           : 第二次请求时间:11ms

源码

https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases

spring-boot-student-mybatis-ehcache 工程

阅读全文
0 0
原创粉丝点击