SpringBoot整合Redis
1、导包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--下面就是Redis的包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置文件的编写
#配置redis
spring.redis.host=127.0.0.1
#设置端口
spring.redis.port=6379
#给数据库设置密码
#spring.redis.password=xxxx
#设置对大的连接数
spring.redis.jedis.pool.max-active=10
#设置线程池中最大的空闲的连接
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=0
#连接池最大的阻塞时间 -1的话那么 表示没有限制
spring.redis.jedis.pool.max-wait=-1ms
3、manager的使用
这里的manager就是service业务逻辑层下沉的,相当于和DAO层同目录,这里面写的主要就是redis这个库的所有访问
@Component //先放入IOC的容器
public class RedisManager {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 向Redis中存放一个键值对
* @param key
* @param value
*/
public void addKeyAndValue(String key,String value){
/**
* stringRedisTemplate.opsForValue(); 这个就是用来操作 String类型的
* stringRedisTemplate.opsForList(); 这个主要就用来操作list的
* stringRedisTemplate.opsForZSet(); 这个主要用来操作sorted set
* stringRedisTemplate.opsForHash(); 用来操作hash结构的
* stringRedisTemplate.opsForSet(); 这个就是用来操作Set数据类型的
*/
stringRedisTemplate.opsForValue().set(key,value);
}
/**
* 通过key获取String类型中的值
* @param key
* @return
*/
public String getValueForKey(String key){
return stringRedisTemplate.opsForValue().get(key);
}
}
4、常见的api说明
/**
* 常用的API的意思
* //设置key过期的API
* stringRedisTemplate.expire("NZ1904",60, TimeUnit.SECONDS);
* //ttl :获取一个键的过期时间
* stringRedisTemplate.getExpire()
* // exists :判断一个键是否存在
* stringRedisTemplate.hasKey("");
* //del :删除一个键值对
* stringRedisTemplate.delete("key");
*incrby 这个命令
* stringRedisTemplate.opsForValue().increment("key",1);
*decrby这个命令
* stringRedisTemplate.opsForValue().increment("key",-1);
*hmget这个命令
*stringRedisTemplate.opsForHash().entries("");
*hmset
*stringRedisTemplate.opsForHash().putAll("",null);
*hset这个命令
*stringRedisTemplate.opsForHash().put();
* hdel命令
*stringRedisTemplate.opsForHash().delete()
* 判断hash结构中这个键是否存在
* stringRedisTemplate.opsForHash().hasKey()
* Set集合中获取某一个值
* stringRedisTemplate.opsForSet().members()
* 判断set集合中是否存在某一个值
*stringRedisTemplate.opsForSet().isMember()
* set集合设置值
* stringRedisTemplate.opsForSet().add()
*/
基于Redis的分布式锁问题Redssion的简单的使用
1、首先是导包
<!--导入redssion这框架包-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.0</version>
</dependency>
2、编写配置文件
@Bean
public RedissonClient redissonClient(){
RedissonClient redissonClient=null;
//获取config的实例
Config config = new Config();
//设置请求的URL地址
String url="redis://106.54.13.167:6379";
//设置config
config.useSingleServer().setAddress(url);
//通过Redisson来创建一个客户端对象
try{
redissonClient= Redisson.create(config);
logger.info("创建RedissonClient成功");
return redissonClient;
}catch (Exception err){
logger.info("创建RedissonClient失败:"+err.fillInStackTrace());
return null;
}
}
3、编写lock的类
@Component
public class DistributeRedisLock {
private Logger logger= LoggerFactory.getLogger(getClass());
@Autowired
private RedissonClient redissonClient;
//一个方法用来加锁
/**
* 加锁成功....
* @param lockName
* @return
*/
public boolean lock(String lockName){
try {
if(null==redissonClient){ //如果对象没有注入进来那么说明是有问题的
logger.info("注入redissonClient对象失败....");
return false;
}
//获取这个锁
RLock lock = redissonClient.getLock(lockName);
//锁住了
lock.lock(30, TimeUnit.SECONDS);
logger.info("加锁成功.......");
return true;
} catch (Exception e) {
logger.info("不可预期的异常造成了加锁失败....");
return false;
}
}
/**
* 释放锁
* @param lockName
* @return
*/
public boolean unlock(String lockName){
try {
if(null==redissonClient){ //说明没法释放出问题了....
logger.info("释放锁失败----"+lockName);
}
//获取到这个锁对象
RLock lock = redissonClient.getLock(lockName);
if(null!=lock){
lock.unlock();
logger.info("释放锁成功....");
return true;
}
return false;
} catch (Exception e) {
logger.info("释放锁失败了....");
return false;
}
}
}
12.4、调用
public String produceStockRedisson(){
String lock="lock";
try {
boolean lock1 = distributeRedisLock.lock(lock);
if(true==lock1){//说明加锁成功
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("traintickes"));
//首先要判断下 这个库存是否>0
if (stock > 0) { //说明可以减去库存
int rStock = stock - 1;
//下一步:将真实的库存放到咋们的Redis中去
stringRedisTemplate.opsForValue().set("traintickes", String.valueOf(rStock));
logger.info("扣减库存成功....剩余库存:" + rStock);
} else { //说明不能扣减库存
logger.info("库存扣减失败、库存是负数、不足...");
} //已经用了15秒钟
}else{
return "当前的排队人数过多...";
}
}finally {
distributeRedisLock.unlock(lock);
}
return "抢票成功....";
}
SpringBoot整合下的键值序列化的话题
为什么键值要序序列化呢?
不同平台之间的数据传输 深拷贝 浅拷贝
Redis的序列化到底是什么?
就是 key 和 value存储到redis中的形式 这个样子是可以自己定义的
1、自定义一个序列化转换器
public class BoboSerializer implements RedisSerializer {
private Class clazz;
public BoboSerializer(Class clazz){
this.clazz=clazz;
}
/**
* 序列化的方法
* 将对象转换成字符串的方法
* @param o
* @return
* @throws SerializationException
*/
@Override
public byte[] serialize(Object o) throws SerializationException {
if(null==o){
return null;
}
//我们要将这个值转换成json对象存储到Redis中
String jsonString = JSON.toJSONString(o);
return jsonString.getBytes(Charset.forName("UTF-8"));
}
/**
* 反序列化
* 将redis中的字符串转换成 java对象的
* @param bytes
* @return
* @throws SerializationException
*/
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if(null==bytes) {
return null;
}
String strResult = new String(bytes);
//将String类型的数据(JSON)转换成java对象
return JSON.parseObject(strResult,clazz);
}
}
Redis开发中的常见问题
1、Redis的缓存穿透
2、Redis下的缓存雪崩的问题
3、Redis的脑裂问题
客户端向主服务器写入了数据 但是主服务器还没有来得及同步的情况下 主服务器死了 那么这个时候就会选举新的主服务器 原来的主服务器在一段时间之后 又好了 那么这个时候 原来的主服务器 只能作为从服务器了 原来主服务器的数据 没有办法进行同步 这种问题 就是redis的脑裂问题
解决方案
min-slaves-to-write 1 这个表示的意思是:在我们客户端写入数据的时候 至少保证 主服务器上有一个从服务器 处于正常连接才能写入这个数据
min-slaves-max-lag 10 :这个表示的的意思是 主从同步的时间 10s
当这两个条件同时存在了就可以解决redis脑裂问题