本文默认Redis已经安装完成,并且可以使用。这里不做Redis的安装等说明
第一步,创建一个基本的SpringBoot应用。我们需要在pom.xml加入Redis的相关依赖。redis的依赖为spring-boot-starter-data-redis和spring-boot-starter-jetty。如下面代码所示:
<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>
<groupId>com.qlys</groupId>
<artifactId>spring-learn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.15.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot 1.4之后开始支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
</project>
我这里另外还使用Mybatis,Mysql,druid等依赖。因为我们下一步需要配置Mybatis的二级缓存。
下一步,修改appliation.yml文件,设置相关的参数。如:
server:
port: 8888
logging:
level:
com.qlys.dao: debug
spring:
datasource:
password: 123456
username: qlys
url: jdbc:mysql://127.0.0.1:3306/bjx-test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
validation-query: select '*'
initial-size: 1
max-active: 20
max-wait: 1000
filters: stat
pool-prepared-statements: true
mybatis:
mapper-locations: classpath*:com/qlys/dao/xml/*.xml
type-aliases-package: com.qlys.dao.mapper
---
spring:
redis:
database: 9
host: 127.0.0.1
port: 6379
password: 123456
pool:
max-idle: 20
max-active: 20
max-wait: -1
min-idle: 0
timeout: 1000
第三步 增加Redis的操作类,我把这个类建立的com.qlys.service包下面,代码如下:
package com.qlys.service;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<Object, Object> redis;
/*
* 读取
*/
public Object read(final Object key) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
return ops.get(key);
}
/*
* 写入
*/
public boolean set(final Object key,Object val) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
ops.set(key, val);
return true;
}
/*
* 设置过期时间
*/
public boolean expire(final Object key,Object val,int expireTime) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
ops.set(key, val);
this.redis.expire(key, expireTime, TimeUnit.SECONDS);
return true;
}
}
其中的RedisTemplate就是SpringBoot为我们封装好的操作Reids的工具类,我们常用的操作都是通过这个对象来完成的。在这个方法中,对于需要设置参数的存储时间是没有直接的方法的。因此我们需要先设置这个参数,然后设置这个参数的时间,即expire方法,先通过ops.set将数据写入redis,然后通过redis.expire方法设置过期时间。
第四步 然后我们就可以写一个代码来测试我们的Redis是否配置成功了,我建立了一个com.qlys.controller来编写界面的测试代码,代码如下:
package com.qlys.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.qlys.service.RedisUtils;
@RestController
public class TestController {
@Autowired
private RedisUtils redis;
@RequestMapping("/save")
public String writeRedis(String key) {
redis.set("key", key);
return "true";
}
@RequestMapping("/read")
public Object readRedis() {
System.out.println(redis.read("key"));
return redis.read("key");
}
}
其中save方法用于将我们传的参数存入redis中,而read方法用于将我们存的值取出来,显示于界面上。
最后修改启动类,来测试我们是否配置成功,代码如下:
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages="com.qlys")
@MapperScan("com.qlys.dao.mapper")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
logger.info("系统启动");
SpringApplication.run(Application.class, args);
}
}
访问我们save和read功能,查看是否成功。如果成功,我们这可以开始我们的redis同mybatis整合操作。
既然要访问数据库,我们当然要写编写数据库相关的代码,由于集成mybatis前面已经讲过,这里我不详细说明,只针对Cache来进行说明
首先建立一个类,实现Cache接口,如下面代码所示:
package com.qlys.bean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
private static RedisTemplate<Object, Object> temp;
public static void setRedisTemplate(RedisTemplate<Object, Object> temp) {
RedisCache.temp = temp;
logger.info("设置缓存对象--{}",temp);
}
private String id;
@Override
public String getId() {
return id;
}
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public void putObject(final Object key,final Object value) {
logger.info("写入缓存");
lock.writeLock().lock();
temp.opsForValue().set(key, value);
lock.writeLock().unlock();
}
@Override
public Object getObject(final Object key) {
logger.info("读取缓存");
return temp.opsForValue().get(key);
}
@Override
public Object removeObject(final Object key) {
logger.info("删除缓存");
Object val = temp.opsForValue().get(key);
temp.delete(key);
return val;
}
@Override
public void clear() {
logger.info("清除缓存");
temp.execute((RedisCallback<Boolean>)(conn)->{
conn.flushDb();
return true;
});
}
@Override
public int getSize() {
logger.info("redis大小");
return temp.execute((RedisCallback<Integer>)(conn)->{
return conn.dbSize().intValue();
});
}
@Override
public ReadWriteLock getReadWriteLock() {
return lock;
}
}
修改上面的RedisUtils类,加入如下代码:
@Bean
public RedisCache redisCache() {
RedisCache.setRedisTemplate(redis);
return null;
}
这个代码是用于将Reids操作类存入到Cache操作类中,由于Cache是通过new创建的,无法通过注入完成。加入完成后,RedisUtils应该是这样的:
package com.qlys.service;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import com.qlys.bean.RedisCache;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<Object, Object> redis;
@Bean
public RedisCache redisCache() {
RedisCache.setRedisTemplate(redis);
return null;
}
/*
* 读取
*/
public Object read(final Object key) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
return ops.get(key);
}
/*
* 写入
*/
public boolean set(final Object key,Object val) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
ops.set(key, val);
return true;
}
/*
* 设置过期时间
*/
public boolean expire(final Object key,Object val,int expireTime) {
ValueOperations<Object,Object> ops = this.redis.opsForValue();
ops.set(key, val);
this.redis.expire(key, expireTime, TimeUnit.SECONDS);
return true;
}
}
最后在我们配置Mybatis语句的mapper.xml文件中加入缓存配置就可以了,代码如下:
<cache eviction="FIFO" flushInterval="1" readOnly="false" type="com.qlys.bean.RedisCache
加入完成后,形成的代码如下:
<?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.qlys.dao.mapper.SystemMapper">
<cache eviction="FIFO" flushInterval="1" readOnly="false" type="com.qlys.bean.RedisCache"></cache>
<select id="select" resultType="map">
SELECT * FROM a_table
<where>
<if test="id!=null">
and a_id=#{id}
</if>
</where>
</select>
<insert id="insert" parameterType="map">
INSERT INTO a_table(a_id,a_name,a_part) VALUES(#{id},#{name},#{part})
</insert>
<delete id="delete" parameterType="map">
delete from a_table where a_id=#{id}
</delete>
</mapper>
至此一个简单的Redis同mybatis集合方案算是完成了。
附:
由于我们有可能会对SpringBoot提供的RedisTemplate的key解析方案做一些改造,这里贴上一个我写的一个序列化方案,方便知道以后怎么修改RedisTemplate这个对象的相关参数。仅供参考:
package com.qlys.bean;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
@Configuration
@EnableCaching
public class RedisCacheConfig {
private static final Logger logger = LoggerFactory.getLogger(RedisCacheConfig.class);
@Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redis) {
return new RedisCacheManager(redis);
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object,Object>();
redisTemplate.setConnectionFactory(factory);
RedisSerializer<Object> redisSerializer = new ByteRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
return redisTemplate;
}
private class ByteRedisSerializer implements RedisSerializer<Object>{
@Override
public byte[] serialize(Object t) throws SerializationException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
// 序列化
oos.writeObject(t);
return baos.toByteArray();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
return null;
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if (bytes == null) {
return null;
}
try (InputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
// 反序列化
return ois.readObject();
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
return null;
}
}
}