之前项目中用到redis缓存,这个在互联网企业中非常常用,这边就建立一个工程基于springboot,数据库用的是mysql连接方式采用的是jpa(也可以是mybits),缓存用的是redis。
Springboot整合Redis有两种方式,分别是Jedis和RedisTemplate,这两者有何区别?
Jedis是Redis官方推荐的面向Java的操作Redis的客户端,而RedisTemplate是SpringDataRedis中对JedisApi的高度封装。其实在Springboot的官网上我们也能看到,官方现在推荐的是SpringDataRedis形式,相对于Jedis来说可以方便地更换Redis的Java客户端,其比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用如:SpringCache。
在这之前我在低版本的Springboot项目中一直使用Jedis操作Redis,但是我也意识到这种做法已经过时了,所以在升级了Springboot版本后特地在此篇中详细梳理一下,以后项目都会使用这个版本的整合方案,不再使用Jedis方式,不过我还是会再写一篇使用Jedis操作Redis的文章,因为从中能很清楚的看到其基本的工作方式,对Redis连接池的手动管理都能更清晰地体现出来。
工程源码github地址:源码地址
我这边现在自己mysql中建立一个数据库test_data,建立表user_info;表结构:
CREATE TABLE `user_info` (
`id` varchar(20) NOT NULL,
`name` varchar(200) DEFAULT NULL,
`age` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC
然后使用idea建立spring boot工程,加入redis依赖,mysql依赖,jpa依赖,我这边最终使用的pom.xml是:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.3.RELEASE
com.test
redis
0.0.1-SNAPSHOT
redis
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
commons-io
commons-io
2.5
org.apache.httpcomponents
httpclient
org.apache.httpcomponents
httpmime
org.apache.poi
poi
3.13
org.apache.poi
poi-ooxml
3.13
org.apache.poi
ooxml-schemas
1.1
com.google.code.gson
gson
2.8.4
com.alibaba
druid
1.1.9
junit
junit
junit
junit
test
org.springframework.boot
spring-boot-maven-plugin
这边配置本地redis 端口号在7006 ,ip是127.0.0.1
对应的配置文件是:
#服务启动端口
server :
port : 9980
#数据库配置
spring:
datasource:
name: test
url: jdbc:mysql://127.0.0.1:3306/test_data?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
redis:
host: 127.0.0.1
#redis密码,没有密码的可以用~表示
password: ~
port: 7006
# pool:
# max-active: 100
# max-idle: 10
# max-wait: 100000
# 日志输出
#logging:
# file: ~/boot.log
# level:
# com.ibatis:DEBUG
# root:DEBUG
task:
cron:0 0/5 * * * ?
几个比较核心的类有,redisService对外接口,UserInfo,UserInfoService,RedisServiceImpl对redis操作主要依赖于redisTemplate这个工具类。
具体代码如下:
redisService:
package com.test.redis.service;
import java.util.List;
public interface RedisService {
boolean set(String key, String value) throws Exception;
String get(String key) throws Exception;
boolean expire(String key, long expire) throws Exception;
boolean setList(String key, List list) throws Exception;
List getList(String key, Class clz) throws Exception;
long lpush(String key, Object obj) throws Exception;
long rpush(String key, Object obj) throws Exception;
void hmset(String key, Object obj) throws Exception;
T hget(String key, Class clz) throws Exception;
void del(String key) throws Exception;
List hmGetAll(String key, Class clz) throws Exception;
String lpop(String key) throws Exception;
}
RedisServiceImpl
package com.test.redis.service.impl;
import com.test.redis.service.RedisService;
import com.test.redis.utils.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
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.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Created by xiaour.github.com on 2017/11/8.
*/
@Service("redisService")
@Transactional(rollbackFor = Exception.class)
public class RedisServiceImpl implements RedisService {
private static int seconds=3600*24;
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean set(final String key, final String value) throws Exception {
Assert.hasText(key,"Key is not empty.");
boolean result = redisTemplate.execute(new RedisCallback() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
connection.set(serializer.serialize(key), serializer.serialize(value));
return true;
}
});
return result;
}
public String get(final String key) throws Exception {
Assert.hasText(key,"Key is not empty.");
String result = redisTemplate.execute(new RedisCallback() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
byte[] value = connection.get(serializer.serialize(key));
return serializer.deserialize(value);
}
});
return result;
}
public void del(final String key) throws Exception {
Assert.hasText(key,"Key is not empty.");
redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection conn) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
return conn.del(serializer.serialize(key));
}
});
}
@Override
public boolean expire(final String key, long expire) {
return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
@Override
public boolean setList(String key, List list) throws Exception {
Assert.hasText(key,"Key is not empty.");
String value = JsonUtil.getJsonString(list);
return set(key,value);
}
@Override
public List getList(String key,Class clz) throws Exception{
Assert.hasText(key,"Key is not empty.");
String json = get(key);
if(json!=null){
List list = JsonUtil.readJson2Array(json,clz);
return list;
}
return null;
}
@Override
public long lpush(final String key, Object obj)throws Exception {
Assert.hasText(key,"Key is not empty.");
final String value = JsonUtil.getJsonString(obj);
long result = redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
long count = connection.lPush(serializer.serialize(key), serializer.serialize(value));
return count;
}
});
return result;
}
@Override
public long rpush(final String key, Object obj) throws Exception{
Assert.hasText(key,"Key is not empty.");
final String value = JsonUtil.getJsonString(obj);
long result = redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
long count = connection.rPush(serializer.serialize(key), serializer.serialize(value));
return count;
}
});
return result;
}
@Override
public void hmset(String key, Object obj) throws Exception{
Assert.hasText(key,"Key is not empty.");
Map data=JsonUtil.readJsonByteMap(JsonUtil.getJsonString(obj));
redisTemplate.execute(new RedisCallback() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
connection.hMSet(serializer.serialize(key),data);
return "";
}
});
}
@Override
public T hget(String key, Class clz) throws Exception{
Assert.hasText(key,"Key is not empty.");
return redisTemplate.execute(new RedisCallback() {
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer serializer = redisTemplate.getStringSerializer();
Map result;
Map data=connection.hGetAll(serializer.serialize(key));
result= new HashMap<>();
for (Map.Entry entry: data.entrySet()) {
result.put(serializer.deserialize(entry.getKey()),serializer.deserialize(entry.getValue()));
}
return JsonUtil.json2Obj(JsonUtil.getJsonString(result),clz);
}
});
}
@Override
public List hmGetAll(String key,Class clz) throws Exception{
Assert.hasText(key,"Key is not empty.");
List
UserInfo
package com.test.redis.domain;
import javax.persistence.Entity;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name="UserInfo")
public class UserInfo {
@Id
private String id;
private String name;
private int age;
public UserInfo() {
}
public UserInfo(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
UserInfoRepository:
package com.test.redis.domain;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserInfoRepository extends PagingAndSortingRepository {
public UserInfo findOneById(String id);
}
对外测试接口
package com.test.redis.web;
import com.test.redis.domain.UserInfo;
import com.test.redis.service.UserInfoService;
import com.test.redis.service.RedisService;
import com.test.redis.utils.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping(value="/test")
public class TestController {
@Autowired
private RedisService redisService;
@Autowired
private UserInfoService userInfoService;
@RequestMapping(value="/index")
public String index(){
return "hello world";
}
/**
* 向redis存储值
* @param key
* @param value
* @return
* @throws Exception
*/
@RequestMapping("/set/{key}/{value}")
public String set(@PathVariable("key")String key, @PathVariable("value")String value) throws Exception{
redisService.set(key, value);
return "success";
}
/**
* 获取redis中的值
* @param key
* @return
*/
@RequestMapping("/get/{key}")
public String get(@PathVariable("key")String key){
try {
return redisService.get(key);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取数据库中的用户
* @param id
* @return
*/
@RequestMapping("/getUser/{id}")
public String getUser(@PathVariable String id){
try {
UserInfo user= userInfoService.findById(id);
return JsonUtil.getJsonString(user);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
@GetMapping( "/getdata")
public String getData()
{
System.out.println("info has been gotten");
return "info got";
}
@RequestMapping(value = "/saveUser/{name}/{age}" , method = RequestMethod.POST)
public String putUser(@PathVariable String name,@PathVariable int age){
try {
userInfoService.saveData(name,age);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static void main(String[] args) {
Map keyMap= new HashMap<>();
keyMap.put("id","编号");
keyMap.put("name","名称");
String [] cnCloumn={"编号","名称"};
System.out.println(Arrays.asList(convertMap(keyMap, cnCloumn)));
}
public static String[] convertMap(Map keyMap,String [] dataList){
for(int i=0;i m:keyMap.entrySet()){
if(m.getValue().equals(dataList[i])){
dataList[i]=m.getKey();
}
}
}
return dataList;
}
public static String getName(String name,String add){
return null;
}
public static void testGetClassName() {
// 方法1:通过SecurityManager的保护方法getClassContext()
String clazzName = new SecurityManager() {
public String getClassName() {
return getClassContext()[1].getName();
}
}.getClassName();
System.out.println(clazzName);
// 方法2:通过Throwable的方法getStackTrace()
String clazzName2 = new Throwable().getStackTrace()[1].getClassName();
System.out.println(clazzName2);
// 方法3:通过分析匿名类名称()
String clazzName3 = new Object() {
public String getClassName() {
String clazzName = this.getClass().getName();
return clazzName.substring(0, clazzName.lastIndexOf('$'));
}
}.getClassName();
System.out.println(clazzName3);
//方法4:通过Thread的方法getStackTrace()
String clazzName4 = Thread.currentThread().getStackTrace()[2].getClassName();
System.out.println(clazzName4);
}
}
测试在mysql中存储数据:postman或者浏览器中输入: localhost:9980/test/saveUser/xxm/89
测试在redis中存储数据:postman或者浏览器中输入:http://localhost:9980/test/set/558/666
我这边通过rdm工具可以看到redis中数据: