redis分兩種呵燕,一種單機(jī) http://www.reibang.com/p/6ac1a3b7745e核行,一種集群 http://www.reibang.com/p/d44aa9a8be2c
首先看spring操作redis的配置枕荞,我項(xiàng)目只用到這些线欲,其他的自行百度。
首先添加依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
然后寫類RedisClient
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
public class RedisClient {
@Autowired
private RedisTemplate redisTemplate;
//set值
public void set(String key, String value) {
try {
redisTemplate.opsForValue().set(key,value);
}catch (Exception e){
e.printStackTrace();
}
}
//get值
public String get(String key) {
try {
return ""+redisTemplate.opsForValue().get(key);
}catch (Exception e){
e.printStackTrace();
return "";
}
}
//自增1
public void incr(String key) {
int num = Integer.parseInt(""+redisTemplate.opsForValue().get(key));
num=num+1;
redisTemplate.opsForValue().set(key,num);
}
//到期時(shí)間
public boolean expire(String key, int second) {
boolean result = redisTemplate.expire(key,second, TimeUnit.SECONDS);
return result;
}
//刪除
public void del(String key) {
redisTemplate.delete(key);
}
//是否存在key
public boolean hasKey(String s) {
Boolean flag = redisTemplate.hasKey(s);
return flag;
}
//左push
public boolean lpush(String key, String value){
boolean flag =false;
try{
redisTemplate.boundListOps(key).leftPush(value);
flag =true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
//右push
public boolean rpush(String key, String value){
boolean flag =false;
try{
redisTemplate.boundListOps(key).rightPush(value);
flag =true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
//添加附近的人
public boolean geoadd(String key,double longitude,double latitude){
boolean flag = false;
try{
redisTemplate.boundGeoOps("nearPeople").geoAdd(new Point(longitude,latitude),key);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
//查詢附近的人
public List geoQuery(double longitude,double latitude) {
List list = null;
try{
list = redisTemplate.opsForGeo().geoRadius("nearPeople", new Circle(new Point(longitude, latitude),
new Distance(500,Metrics.KILOMETERS)),
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates()).getContent();
}catch (Exception e){
e.printStackTrace();
}
return list;
}
}
注意:
我用的是RedisTemplate
否过,在這之前我用的是redis.clients.jedis.JedisPool
狱从,但是每次操作就第一次,可以叠纹,稍微快速刷新兩次就一直阻塞,代碼
public void set(String key, String value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
} finally {
//返還到連接池
jedis.close();
}
}
具體原因沒弄明白敞葛,好像和最大連接數(shù)有關(guān)誉察,之后發(fā)現(xiàn)不行,才換成RedisTemplate
單機(jī)配置
配置文件application.properties
添加
# Redis數(shù)據(jù)庫索引(默認(rèn)為0)
spring.redis.database=0
# Redis服務(wù)器地址
spring.redis.host=172.16.255.231
# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
spring.redis.pool.max-active=8
# 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.pool.max-idle=8
# 連接池中的最小空閑連接
spring.redis.pool.min-idle=1
# 連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=5000
類Controller中測試
@Controller
@RequestMapping("/hello")
public class HelloController {
@Autowired
private HelloService helloService;
@Autowired
private RedisClient redisClient;
@RequestMapping(value = "/testRedis",method = RequestMethod.GET)
@ResponseBody
public String testRedis(@RequestParam String userId){
if (redisClient.hasKey(userId)){
System.out.println("redis中用戶存在");
return redisClient.get(userId);
}
User user = new User();
user.setId("1");
user.setUsername("lijia");
redisClient.set(userId,JSON.toJSONString(user));
System.out.println("redis中用戶不存在,現(xiàn)在已設(shè)定");
return JSON.toJSONString(user);
}
}
啟動(dòng)Application惹谐,然后再瀏覽器中輸入 http://localhost:8080/hello/testRedis?userId=1
兩次都能返回結(jié)果持偏,但是一次是從redis中讀取的,一次是直接獲取的
這樣redis單機(jī)環(huán)境就搭建好了氨肌。
集群配置
還是修改application.properties
spring.redis.cluster.nodes=172.16.255.231:7001,172.16.255.231:7002,172.16.255.231:7003,172.16.255.231:7004,172.16.255.231:7005,172.16.255.231:7006
然后讀取這個(gè)配置文件
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class RedisClusterProperties {
//集群節(jié)點(diǎn)
private List<String> nodes=new ArrayList<>();
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}
配置
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Configuration
@ConditionalOnClass(RedisClusterConfig.class)
@EnableConfigurationProperties(RedisClusterProperties.class)
public class RedisClusterConfig {
@Resource
private RedisClusterProperties redisClusterProperties;
@Bean
public JedisCluster redisCluster(){
Set<HostAndPort> nodes = new HashSet<>();
for (String node:redisClusterProperties.getNodes()){
String[] parts= StringUtils.split(node,":");
Assert.state(parts.length==2, "redis node shoule be defined as 'host:port', not '" + Arrays.toString(parts) + "'");
nodes.add(new HostAndPort(parts[0], Integer.valueOf(parts[1])));
}
return new JedisCluster(nodes);
}
}
最后還是測試類鸿秆,上面的一樣,但是判斷key方式不一樣
import com.alibaba.fastjson.JSON;
import com.lijia.bean.User;
import com.lijia.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import redis.clients.jedis.JedisCluster;
@Controller
@RequestMapping("/hello")
public class HelloController {
@Autowired
private HelloService helloService;
@Autowired
private JedisCluster jedisCluster;
@RequestMapping(value = "/testRedis",method = RequestMethod.GET)
@ResponseBody
public String testRedis(@RequestParam String userId){
if (jedisCluster.exists(userId)){
System.out.println("redis集群中用戶存在");
return jedisCluster.get(userId);
}
User user = new User();
user.setId("1");
user.setUsername("lijia");
jedisCluster.set(userId,JSON.toJSONString(user));
System.out.println("redis集群中用戶不存在,現(xiàn)在已設(shè)定");
return JSON.toJSONString(user);
}
}
啟動(dòng)Application怎囚,然后再瀏覽器中輸入 http://localhost:8080/hello/testRedis?userId=1
兩次都能返回結(jié)果卿叽,但是一次是從redis中讀取的,一次是直接獲取的
這集群算是可以用了恳守。
注意:
今天再用linux中連接redis考婴,發(fā)現(xiàn)連接集群中,需要加上-c催烘,這個(gè)是必須的沥阱,不然set和get報(bào)錯(cuò)。
JedisPool假死
如果用jedisPool去set和get伊群。首先會(huì)有一段jedis = jedisPool.getResource();
考杉,
就是當(dāng)連接池耗盡的時(shí)候
BlockWhenExhausted:連接耗盡時(shí)是否阻塞, false報(bào)異常,ture阻塞直到超時(shí), 默認(rèn)true
max-wait:獲取連接時(shí)的最大等待毫秒數(shù)(如果設(shè)置為阻塞時(shí)BlockWhenExhausted),如果超時(shí)就拋異常,小于零:阻塞不確定的時(shí)間, 默認(rèn)-1
由于BlockWhenExhausted默認(rèn)為true,連接耗盡時(shí)會(huì)阻塞到超時(shí)舰始,但是MaxWaitMillis默認(rèn)為-1崇棠,超時(shí)時(shí)間是一個(gè)不確定的時(shí)間,所以就一直阻塞著了蔽午。
設(shè)置redis.pool.max-wait值易茬。
RedisTemplate亂碼現(xiàn)象
使用了RedisTemplate之后,今天測試之后發(fā)現(xiàn)redis找不到key,但是出現(xiàn)了下面這種情況抽莱。
原因是:
spring-data-redis的RedisTemplate<K, V>模板類在操作redis時(shí)默認(rèn)使用JdkSerializationRedisSerializer來進(jìn)行序列化
因?yàn)閟pring操作redis是在jedis客戶端基礎(chǔ)上進(jìn)行的范抓,而jedis客戶端與redis交互的時(shí)候協(xié)議中定義是用byte類型交互,jedis中提供了string類型轉(zhuǎn)為byte[]類型食铐,
但是看到spring-data-redis中RedisTemplate<K, V>在操作的時(shí)候k匕垫,v是泛型的,所以RedisTemplate中有了上面那段代碼虐呻,在沒有特殊定義的情況下象泵,
spring默認(rèn)采用defaultSerializer = new JdkSerializationRedisSerializer();來對key,value進(jìn)行序列化操作斟叼。
把原來的
@Autowired
private RedisTemplate redisTemplate;
修改為:
private RedisTemplate redisTemplate;
@Autowired(required = false)
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
this.redisTemplate = redisTemplate;
}
然后再試試就好了偶惠。