一、Redis环境

Redis 官网 :http://redis.io/

windows下载:https://github.com/dmajkic/redis/downloads

1、文件解压缩

2、启动Redis服务器

3、启动Redis客户端

4、测试Redis缓存

redis-cli.exe -h 127.0.0.1 -p 6379

set keytest valuestest 根据key、value加入缓存

get keytest 根据key获取值

flushall 清空所有缓存

5、设置Redis密码

6、conf配置文件

#是否以后台守护进程运行,默认为no, 取值yes, no
daemonize no #pid文件存放路径
pidfile /var/run/redis.pid #配置redis端口,默认6379
port 6379 #绑定ip。默认绑定所有本机ip,一般用在服务器多ip下,可以只监听内网服务器ip,保证服务安全
bind 127.0.0.1 #sock文件
unixsocket /tmp/redis.sock #客户端超时时间,单位秒
timeout 300 #log级别,支持四个级别,debug,notice,verbose,warning
loglevel verbose #log文件路径
logfile #log输出到标准设备,logs不写文件,输出到空设备,/deb/null
logfile stdout #保存快照的频率,在多长时间内执行一定数量的写操作时,保存快照的频率,可以设置多个条件。如果都注释掉,则不做内存数据持久化。如果只是把redis只用作cache,不开启持久化功能
save <seconds> <changes>
save 900 1 #是否使用压缩
rdbcompression #快照数据库名称
dbfilename #数据库存放路径
dir #redis主从 做法 在从上填上主的IP和端口号 主上不用做任何设置
slaveof <masterip> <masterport> #主库服务器口令,如果主服务器未打开requirepass,则不需要此项
masterauth <master-password> #在master服务器挂掉或者同步失败时,从服务器是否继续提供服务
slave-serve-stale-data yes #设置redis服务密码,如果开启,则客户端连接时需要 -a 指定密码,否则操作会提示无权限
requirepass foobared #命令改名,相当于linux alias,可以用改功能屏蔽一些危险命令
rename-command #最大连接数;0 表示不限制
maxclients 128 #最大使用内存(分配的内存),推荐生产环境下做相应调整,我们用的是只用来做高速缓存,限制2G。默认情况下,redis会占用可用的所有内存
maxmemory <bytes> #过期策略,提供六种策略
maxmemory-policy volatile-lru
volatile-lru //删除过期和lru 的key(默认值)
allkeys-lru //删除lru算法的key
volatile-random //随机删除即将过期key
allkeys->random //随机删除
volatile-ttl //删除即将过期的
noeviction //永不过期,返回错误 #是否开启appendonlylog,开启的话每次写操作会记一条log。相当于mysql的binlog;不同的是,每次redis启动都会读此文件构建完整数据。即使删除rdb文件,数据也是安全的
appendonly #日志文件的名称,默认appendonly.aof
appendfilename appendonly.aof #异步写append file 的策略。类似mysql事物log写方式。三种
appendfsync
appendfsync always //同步,每次写都要flush到磁盘,安全,速度慢。
appendfsync everysec //每秒写(默认值,推荐值)同mysql
appendfsync no //交给操作系统去做flush的动作 #虚拟内存开关
vm-enabled no #swap文件,不同redis swap文件不能共享。而且生产环境下,不建议放在tmp目录
vm-swap-file /tmp/redis.swap #vm大小限制。0:不限制,建议60-80% 可用内存大小
vm-max-memory 0 #根据缓存内容大小调整,默认32字节
vm-page-size 32 #page数。每 8 page,会占用1字节内存。vm-page-size * vm-pages 等于 swap 文件大小
vm-pages 134217728 #vm 最大io线程数。注意: 0 标志禁止使用vm
vm-max-threads 4

二、实现Redis缓存

1、整体思路

  • 参考Ehcache实现MyBatis二级缓存代码(Maven引用对应jar查阅)
  • 使用Spring管理Redis连接池
  • 模仿EhcacheCache,实现RedisCache

2、pom.xml中加入Maven依赖

<!-- spring-redis实现 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.2.RELEASE</version>
</dependency>
<!-- redis客户端jar -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>

3、引入applicationContext.xml中引入redis配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- redis数据源 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- Spring-redis连接池管理工厂 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>
<!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 -->
<bean id="redisCacheTransfer" class="com.hsmdata.springTest.modules.cache.RedisCacheTransfer">
<property name="jedisConnectionFactory" ref="jedisConnectionFactory"/>
</bean>
</beans>

4、redis.properties配置文件

#============================#
#==== Redis settings ====#
#============================#
#redis 服务器 IP
redis.host=127.0.0.1 #redis 服务器端口
redis.port=6379 #redis 密码
redis.pass= #redis 支持16个数据库(相当于不同用户)可以使不同的应用程序数据彼此分开同时又存储在相同的实例上
redis.dbIndex=3 #redis 缓存数据过期时间单位秒(3600*12 = 43 200)
redis.expiration=43200 #控制一个 pool 最多有多少个状态为 idle 的jedis实例
redis.maxIdle=200 #控制一个 pool 可分配多少个jedis实例
redis.maxActive=1000 #当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
redis.maxWait=500 #在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的;
redis.testOnBorrow=true

5、创建缓存实现类RedisCache

package com.hsmdata.springTest.modules.cache;

import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.exceptions.JedisConnectionException; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* @author
* 2018-04-10 20:50
* $DESCRIPTION}
*/ public class RedisCache implements Cache
{
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private static JedisConnectionFactory jedisConnectionFactory; private final String id; /**
* The {@code ReadWriteLock}.
*/
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.debug("MybatisRedisCache:id=" + id);
this.id = id;
} @Override
public void clear()
{
JedisConnection connection = null;
try
{
connection = jedisConnectionFactory.getConnection();
connection.flushDb();
connection.flushAll();
}
catch (JedisConnectionException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.close();
}
}
} @Override
public String getId()
{
return this.id;
} @Override
public Object getObject(Object key)
{
Object result = null;
JedisConnection connection = null;
try
{
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
result = serializer.deserialize(connection.get(serializer.serialize(key)));
}
catch (JedisConnectionException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.close();
}
}
return result;
} @Override
public ReadWriteLock getReadWriteLock()
{
return this.readWriteLock;
} @Override
public int getSize()
{
int result = 0;
JedisConnection connection = null;
try
{
connection = jedisConnectionFactory.getConnection();
result = Integer.valueOf(connection.dbSize().toString());
}
catch (JedisConnectionException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.close();
}
}
return result;
} @Override
public void putObject(Object key, Object value)
{
JedisConnection connection = null;
try
{
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
connection.set(serializer.serialize(key), serializer.serialize(value));
}
catch (JedisConnectionException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.close();
}
}
} @Override
public Object removeObject(Object key)
{
JedisConnection connection = null;
Object result = null;
try
{
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
result =connection.expire(serializer.serialize(key), 0);
}
catch (JedisConnectionException e)
{
e.printStackTrace();
}
finally
{
if (connection != null) {
connection.close();
}
}
return result;
} public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
RedisCache.jedisConnectionFactory = jedisConnectionFactory;
} }

6、创建中间类RedisCacheTransfer,完成RedisCache.jedisConnectionFactory的静态注入

package com.hsmdata.springTest.modules.cache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; /**
* @author
* 2018-04-10 20:52
* $DESCRIPTION}
*/ public class RedisCacheTransfer {
@Autowired
public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
RedisCache.setJedisConnectionFactory(jedisConnectionFactory);
}
}

7、mapper中加入MyBatis二级缓存

<mapper namespace="com.hsmdata.springTest.modules.mapper.UserMapper" >
<!--开启本mapper的二级缓存,隔10秒自动刷新缓存 flushInterval="10000" -->
<cache type="com.hsmdata.springTest.modules.cache.RedisCache" />

8、Mybatis全局开启二级缓存

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 开启二级缓存,默认是false -->
<setting name="cacheEnabled" value="true"/> <!--resultMap中的association和collection标签具有延迟加载的功能。-->
<!--延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息。--> <!-- lazyLoadingEnabled:延迟加载启动,默认是false
全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。-->
<setting name="lazyLoadingEnabled" value="false"/> <!-- aggressiveLazyLoading:积极的懒加载,false的话按需加载,默认是true
当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。-->
<setting name="aggressiveLazyLoading" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25000"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>

9、测试

package com.springTest.mybatis.cache;

import com.hsmdata.springTest.modules.entity.User;
import com.hsmdata.springTest.modules.mapper.UserMapper;
import com.hsmdata.springTest.modules.service.UserService;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /**
* @author
* 2018-04-10 15:11
* $DESCRIPTION}
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:/config/applicationContext.xml", "classpath:/config/spring-servlet.xml"})
public class CacheTest {
@Autowired
private UserService userService;
@Autowired
private SqlSessionFactory sqlSessionFactory; /**
* 同一个sqlSession
*/
@Test
public void testFirstCache(){
SqlSession sqlSession=sqlSessionFactory.openSession();
UserMapper userMapper= sqlSession.getMapper(UserMapper.class);
User user=userMapper.selectByPrimaryKey(56);
System.out.println(user); /* 对sqlsession执行commit操作,也就意味着用户执行了update、delete等操作,那么数据库中的数据势必会发生变化,如果用户请求数据仍然使用之前内存中的数据,那么将读到脏数据。
所以在执行sqlsession操作后,会清除保存数据的HashMap,用户在发起查询请求时就会重新读取数据并放入一级缓存中了。*/
// sqlSession.commit(); user=userMapper.selectByPrimaryKey(56);
System.out.println(user);
} /**
* 不同的sqlSession
*/
@Test
public void testSecondaryCache(){
SqlSession sqlSession=sqlSessionFactory.openSession();
UserMapper userMapper= sqlSession.getMapper(UserMapper.class);
User user=userMapper.selectByPrimaryKey(56);
System.out.println(user); // 即使开启了二级缓存,不同的sqlsession之间的缓存数据也不是想互访就能互访的,必须等到sqlsession关闭了以后,才会把其一级缓存中的数据写入二级缓存。
// 关闭session
// sqlSession.close(); // 通过sqlSessionFactory创建一个新的session
sqlSession=sqlSessionFactory.openSession();
// 获取mapper对象
userMapper=sqlSession.getMapper(UserMapper.class); user=userMapper.selectByPrimaryKey(56);
System.out.println(user);
} /**
* 不同的sqlSession
*/
@Test
public void testSecondaryCache2() {
/* User user=new User("cache","123456","cache","","male",20);
userService.insert(user);*/ User user = userService.get(56);
System.out.println(user); User user1 = userService.get(56);
System.out.println(user1);
} @Test
public void testFirstCache2() {
/* User user=new User("cache","123456","cache","","male",20);
userService.insert(user);*/ User user = userService.getTwo(56);
System.out.println(user);
} @Test
public void testRedisCache(){
User user=userService.get(55);
System.out.println(user); User user2=userService.get(56);
System.out.println(user2); User user3=userService.get(55);
System.out.println(user3); } }
 

Spring + MySQL + Mybatis + Redis【二级缓存】的更多相关文章

  1. Spring Boot + Mybatis + Redis二级缓存开发指南

    Spring Boot + Mybatis + Redis二级缓存开发指南 背景 Spring-Boot因其提供了各种开箱即用的插件,使得它成为了当今最为主流的Java Web开发框架之一.Mybat ...

  2. Spring + MySQL + Mybatis + Redis【二级缓存】执行流程分析

    一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就 ...

  3. Redis集成到Spring做mybatis做二级缓存

    一.原理: 要缓存的 Java 对象必须实现 Serializable 接口,因为 Spring 会将对象先序列化再存入 Redis,比如本文中的 com.defonds.bdp.city.bean. ...

  4. springboot mybatis redis 二级缓存

    前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace. 即,在不同的sqlsession中,相同的namespace下,相同 ...

  5. spring+springmvc+mybatis+redis实现缓存

    先搭建好redis环境 需要的jar如下: jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:330 ...

  6. 使用Redis做MyBatis的二级缓存

    使用Redis做MyBatis的二级缓存 通常为了减轻数据库的压力,我们会引入缓存.在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了. 如果没有才去 ...

  7. Redis实现Mybatis的二级缓存

    一.Mybatis的缓存 通大多数ORM层框架一样,Mybatis自然也提供了对一级缓存和二级缓存的支持.一下是一级缓存和二级缓存的作用于和定义. 1.一级缓存是SqlSession级别的缓存.在操作 ...

  8. Mybatis使用Redis二级缓存

    在Mybatis中允许开发者自定义自己的缓存,本文将使用Redis作为Mybatis的二级缓存.在Mybatis中定义二级缓存,需要如下配置: 1. MyBatis支持二级缓存的总开关:全局配置变量参 ...

  9. mybatis整合redis二级缓存

    mybatis默认开启了二级缓存功能,在mybatis主配置文件中,将cacheEnabled设置成false,则会关闭二级缓存功能 <settings> <!--二级缓存默认开启, ...

随机推荐

  1. Hybris ECP(Enterprise Commerce Platform)的调试

    This blog is written to demonstrate how to setup debug environment for Hybris ECP(Enterprise Commerc ...

  2. Python 操作Redis 转载篇

    Python操作Redis数据库 连接数据库 StrictRedis from redis import StrictRedis # 使用默认方式连接到数据库 redis = StrictRedis( ...

  3. datatable 动态显示/隐藏列

    这个例子演示了 column().visible()方法来隐藏显示列,通过点击列按钮动态切换 <table id="example" class="display& ...

  4. Android数字签名解析(一)

     一.数字签名概述 所谓"数字签名"就是通过某种password运算生成一系列符号及代码组成电子password进行签名,来取代书写签名或印章. 数字签名有两种功效:一是能确定消息 ...

  5. luogu P3796【模板】AC自动机(加强版)

    嘟嘟嘟 这个和某谷的AC自动机模板简单版差不多. 但还是要注意几点的: 1.这个是统计出现次数,而不是是否出现,所以在查询的时候加上这个节点的val后,不能把val标记为-1.那么也就可以说查询的时间 ...

  6. Android学习笔记_63_手机安全卫士知识点归纳(3)分享 程序锁 服务 进程管理 widget

    1.分享: Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setT ...

  7. HDU 1210 Eddy's 洗牌问题(找规律,数学)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1210 Eddy's 洗牌问题 Time Limit: 2000/1000 MS (Java/Other ...

  8. socket 代码实例

    ​ 1. TCP SOCKET 客户端: #!/usr/bin/env python # -*-coding:utf-8 -*- import socket HOST = 'localhost' PO ...

  9. js 防抖 节流 JavaScript

    实际工作中,通过监听某些事件,如scroll事件检测滚动位置,根据滚动位置显示返回顶部按钮:如resize事件,对某些自适应页面调整DOM的渲染:如keyup事件,监听文字输入并调用接口进行模糊匹配等 ...

  10. requirements.txt 快速备份与安装项目所需安装包

    在查看项目时,通常会有一个requirements.txt 文件, requirements.txt 文件是用于记录所有依赖包及其精确的版本号,便于项目在其它电脑时新环境部署构建项目所需要的运行环境. ...