Spring Boot + Mybatis + Redis二級(jí)緩存實(shí)例

二級(jí)緩存是多個(gè)SqlSession共享的,其作用域是mapper的同一個(gè)namespace,不同的sqlSession兩次執(zhí)行相同namespace下的sql語(yǔ)句且向sql中傳遞參數(shù)也相同即最終執(zhí)行相同的sql語(yǔ)句,第一次執(zhí)行完畢會(huì)將數(shù)據(jù)庫(kù)中查詢(xún)的數(shù)據(jù)寫(xiě)到緩存(內(nèi)存),第二次會(huì)從緩存中獲取數(shù)據(jù)將不再?gòu)臄?shù)據(jù)庫(kù)查詢(xún),從而提高查詢(xún)效率。Mybatis默認(rèn)沒(méi)有開(kāi)啟二級(jí)緩存需要在setting全局參數(shù)中配置開(kāi)啟二級(jí)緩存。

下面是使用Redis來(lái)作為Mybatis二級(jí)緩存的實(shí)例:

Redis的安裝使用的是Docker,Docker的簡(jiǎn)介

application.properties

在application.properties文件中配置Redis,Mybatis,開(kāi)啟Mybatis二級(jí)緩存等:

server.port=80
# 數(shù)據(jù)源配置
spring.datasource.url=jdbc:mysql://localhost:3306/ssb_test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.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
#開(kāi)啟MyBatis的二級(jí)緩存
mybatis.configuration.cache-enabled=true

#pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql

#日志配置
logging.level.com.xiaolyuh=debug
logging.level.org.springframework.web=debug
logging.level.org.springframework.transaction=debug
logging.level.org.mybatis=debug

#redis
#database name
spring.redis.database=0
#server host
spring.redis.host=192.168.195.128
#server password
spring.redis.password=
#connection port
spring.redis.port=6378
#spring.redis.pool.max-idle=8 # pool settings ...
#spring.redis.pool.min-idle=0
#spring.redis.pool.max-active=8
#spring.redis.pool.max-wait=-1
#spring.redis.sentinel.master= # name of Redis server
#spring.redis.sentinel.nodes= # comma-separated list of host:port pairs

debug=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-redis</artifactId>
    <packaging>jar</packaging>

    <name>spring-boot-student-mybatis-redis</name>
    <description>Demo Mybatis Redis 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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</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>org.mybatis</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>

</project>

Redis配置類(lèi)替換序列化實(shí)現(xiàn)方式

package com.xiaolyuh.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    /**
     * 重寫(xiě)Redis序列化方式,使用Json方式:
     * 當(dāng)我們的數(shù)據(jù)存儲(chǔ)到Redis的時(shí)候,我們的鍵(key)和值(value)都是通過(guò)Spring提供的Serializer序列化到數(shù)據(jù)庫(kù)的。RedisTemplate默認(rèn)使用的是JdkSerializationRedisSerializer,StringRedisTemplate默認(rèn)使用的是StringRedisSerializer。
     * Spring Data JPA為我們提供了下面的Serializer:
     * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
     * 在此我們將自己配置RedisTemplate并定義Serializer。
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 設(shè)置值(value)的序列化采用Jackson2JsonRedisSerializer。
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // 設(shè)置鍵(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

Spring容器獲取Bean工具類(lèi)

通過(guò)Spring Aware(容器感知)來(lái)獲取到ApplicationContext,然后根據(jù)ApplicationContext獲取容器中的Bean。

package com.xiaolyuh.holder;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 以靜態(tài)變量保存Spring ApplicationContext, 可在任何代碼任何地方任何時(shí)候中取出ApplicaitonContext.
 */
@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    /**
     * 實(shí)現(xiàn)ApplicationContextAware接口的context注入函數(shù), 將其存入靜態(tài)變量.
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext; // NOSONAR
    }

    /**
     * 取得存儲(chǔ)在靜態(tài)變量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 從靜態(tài)變量ApplicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類(lèi)型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 從靜態(tài)變量ApplicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類(lèi)型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    /**
     * 清除applicationContext靜態(tài)變量.
     */
    public static void cleanApplicationContext() {
        applicationContext = null;
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext未注入,請(qǐng)?jiān)赼pplicationContext.xml中定義SpringContextHolder");
        }
    }
}

自定的Mybatis緩存

自定義緩存需要實(shí)現(xiàn)Mybatis的Cache接口,我這里將使用Redis來(lái)作為緩存的容器。

package com.xiaolyuh.cache;

import com.xiaolyuh.holder.SpringContextHolder;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 使用Redis來(lái)做Mybatis的二級(jí)緩存
 * 實(shí)現(xiàn)Mybatis的Cache接口
 */
public class MybatisRedisCache implements Cache {

    private static final Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);

    // 讀寫(xiě)鎖
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    private RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");

    private String id;

    public MybatisRedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        logger.info("Redis Cache id " + id);
        this.id = id;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public void putObject(Object key, Object value) {
        if (value != null) {
            // 向Redis中添加數(shù)據(jù),有效時(shí)間是2天
            redisTemplate.opsForValue().set(key.toString(), value, 2, TimeUnit.DAYS);
        }
    }

    @Override
    public Object getObject(Object key) {
        try {
            if (key != null) {
                Object obj = redisTemplate.opsForValue().get(key.toString());
                return obj;
            }
        } catch (Exception e) {
            logger.error("redis ");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        try {
            if (key != null) {
                redisTemplate.delete(key.toString());
            }
        } catch (Exception e) {
        }
        return null;
    }

    @Override
    public void clear() {
        logger.debug("清空緩存");
        try {
            Set<String> keys = redisTemplate.keys("*:" + this.id + "*");
            if (!CollectionUtils.isEmpty(keys)) {
                redisTemplate.delete(keys);
            }
        } catch (Exception e) {
        }
    }

    @Override
    public int getSize() {
        Long size = (Long) redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.dbSize();
            }
        });
        return size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }
}

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">

    <cache type="com.xiaolyuh.cache.MybatisRedisCache">
        <property name="eviction" value="LRU" />
        <property name="flushInterval" value="6000000" />
        <property name="size" value="1024" />
        <property name="readOnly" value="false" />
    </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>

    <!-- 對(duì)這個(gè)語(yǔ)句useCache="true"默認(rèn)是true,可以不寫(xiě) -->
    <select id="findAll" resultMap="BaseResultMap" useCache="true">
        select
        <include refid="Base_Column_List"/>
        from person
    </select>

    <!-- 對(duì)這個(gè)語(yǔ)句禁用二級(jí)緩存 -->
    <select id="findByPage" resultMap="BaseResultMap" useCache="false">
        select
        <include refid="Base_Column_List"/>
        from person
    </select>
</mapper>

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,也可以在配置類(lèi)上使用@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);

    /**
     * 獲取所有數(shù)據(jù)
     * @return
     */
    List<Person> findAll();

    /**
     * 分頁(yè)查詢(xún)數(shù)據(jù)
     * @return
     */
    Page<Person> findByPage();
}

實(shí)體類(lèi)

package com.xiaolyuh.domain.model;

import java.io.Serializable;

public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    /**
     * 名稱(chēng)
     */
    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}

Service接口

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();

    /**
     * 分頁(yè)查詢(xún)
     * @param pageNo 頁(yè)號(hào)
     * @param pageSize 每頁(yè)顯示記錄數(shù)
     * @return
     */
    Page<Person> findByPage(int pageNo, int pageSize);

    void insert(Person person);
}

Service實(shí)現(xiàn)類(lèi)

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);
    }


}

測(cè)試類(lèi)

package com.xiaolyuh;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.xiaolyuh.domain.model.Person;
import com.xiaolyuh.holder.SpringContextHolder;
import com.xiaolyuh.service.PersonService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonMapperTests {

    private Logger logger = LoggerFactory.getLogger(PersonMapperTests.class);

    @Autowired
    private PersonService personService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    Person person = null;

    @Before
    public void testInsert() {
        person = new Person();
        person.setName("測(cè)試");
        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));
    }

    // 測(cè)試mybatis緩存
    @Test
    public void testCache() {
        long begin = System.currentTimeMillis();
        List<Person> persons = personService.findAll();
        long ing = System.currentTimeMillis();
        personService.findAll();
        long end = System.currentTimeMillis();
        logger.debug("第一次請(qǐng)求時(shí)間:" + (ing - begin) + "ms");
        logger.debug("第二次請(qǐng)求時(shí)間:" + (end - ing) + "ms");

        Assert.assertNotNull(persons);
        logger.debug(JSON.toJSONString(persons));
    }

    // 測(cè)試Redis存儲(chǔ)和獲取一個(gè)List
    @Test
    public void testRedisCacheSetList() {
        List<Person> persons = new ArrayList<>();
        persons.add(person);
        persons.add(person);
        persons.add(person);
        redisTemplate.opsForValue().set(person.getId() + "", persons, 2, TimeUnit.MINUTES);
        persons = (List<Person>) redisTemplate.opsForValue().get(person.getId() + "");
        System.out.println(JSON.toJSONString(persons));
    }

    // 測(cè)試Redis存儲(chǔ)和獲取一個(gè)Object
    @Test
    public void testRedisCacheSetObject() {
        redisTemplate.opsForValue().set(person.getId() + "", person, 2, TimeUnit.MINUTES);
        Object p = redisTemplate.opsForValue().get(person.getId() + "");
        if (p instanceof Person) {
            Person person1 = (Person) p;
            System.out.println(JSON.toJSONString(person1));
        }
    }

    // 測(cè)試 通過(guò)Spring Aware獲取Spring容器中的額Bean
    @Test
    public void testApplicationContextAware() {
        RedisTemplate redisTemplate = SpringContextHolder.getBean("redisTemplate");
        System.out.println(redisTemplate);
    }

}

日志

2017-06-29 15:22:22.351 DEBUG 12976 --- [           main] com.xiaolyuh.domain.mapper.PersonMapper  : Cache Hit Ratio [com.xiaolyuh.domain.mapper.PersonMapper]: 0.5
2017-06-29 15:22:22.351 DEBUG 12976 --- [           main] org.mybatis.spring.SqlSessionUtils       : Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2a4332]
2017-06-29 15:22:22.351 DEBUG 12976 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2a4332]
2017-06-29 15:22:22.351 DEBUG 12976 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2a4332]
2017-06-29 15:22:22.351 DEBUG 12976 --- [           main] org.mybatis.spring.SqlSessionUtils       : Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2a4332]
2017-06-29 15:22:22.353 DEBUG 12976 --- [           main] com.xiaolyuh.PersonMapperTests           : 第一次請(qǐng)求時(shí)間:92ms
2017-06-29 15:22:22.354 DEBUG 12976 --- [           main] com.xiaolyuh.PersonMapperTests           : 第二次請(qǐng)求時(shí)間:68ms

源碼

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

spring-boot-student-mybatis-redis工程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容