1.Redis是线程安全的,但是高并发时出现数据不安全的问题;
2.解决办法,加锁,Redission分布式锁的使用;
3.Redis项目应用,图书的抢购,不加锁,数据不安全;
4.加了Redission中间件,保证原子性,数据安全;
Redisson是一个基于Redis的Java驻留内存数据网格(In-Memory Data Grid)。它封装了Redis客户端API,并提供了一个分布式锁、分布式集合、分布式对象、分布式Map等常用的数据结构和服务。
org.redisson
redisson-spring-boot-starter
3.21.3
@Configuration
public class RedissionConfig {
@Value("${spring.redis.host}")
private String host;
// @Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.setTransportMode(TransportMode.EPOLL);
config.useSingleServer().setAddress("redis://192.168.198.130:6379");
return Redisson.create(config);
}
}
@Autowired
private RedissonClient redissonClient;
// 1.获取锁对象
RLock myLock = redissonClient.getLock("myLock");
try{
// 2.准备锁代码,并进行加锁
myLock.lock();
}finally{
// 3.解除锁
myLock.unlock(); // 把锁释放
}
java.lang.NoClassDefFoundError: org/springframework/data/redis/connection/zset/Tuple
org.springframework.data.redis.connection.zset.Tuple
<dependency>
<groupId>org.redissongroupId>
<artifactId>redisson-spring-boot-starterartifactId>
<version>3.9.1version>
dependency>
controller层的代码
package com.tianju.redisDemo.controller;
import com.tianju.redisDemo.dto.HttpResp;
import com.tianju.redisDemo.dto.ResultCode;
import com.tianju.redisDemo.service.IBookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@Controller
@RequestMapping("/api/book")
@Slf4j
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping("/rush")
public HttpResp rushBook(String key){
Integer rushBuy = bookService.rushBuy(key);
// 如果为null,说明图书还没进入抢购的队列
if (rushBuy==null){
return HttpResp.results(ResultCode.BOOK_RUSH_ERROR,new Date(),"图书还不能秒杀抢购");
}
log.debug("》》》》图书剩余库存:"+rushBuy);
return HttpResp.results(ResultCode.BOOK_RUSH_SUCCESS,new Date(),null);
}
}
service层的代码
package com.tianju.redisDemo.service.impl;
import com.tianju.redisDemo.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class IBookServiceImpl implements IBookService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Integer rushBuy(String key) {
String numStr = stringRedisTemplate.opsForValue().get(key);
if (numStr==null){
return null; // 商品剩余数量还没有进入缓存,不能抢购
}
int num = Integer.parseInt(numStr);
// 如果库存数量大于1;执行-1,去库存操作
if (num>0){
num--; // 去库存
// 更新当前库存数量
stringRedisTemplate.opsForValue().set(key, String.valueOf(num));
}
return num;
}
}
application.yml配置文件
server:
port: 9099
spring:
# redis的相关配置
redis:
host: localhost
port: 6379
database: 0
# 日志需要配置一下
logging:
level:
com.tianju.redisDemo: debug
Redisson是一个基于Redis的Java驻留内存数据网格(In-Memory Data Grid)。它封装了Redis客户端API,并提供了一个分布式锁、分布式集合、分布式对象、分布式Map等常用的数据结构和服务。
要点:
@Autowired private RedissonClient redissonClient; @Override public Integer rushBuy(String key) { // 1.获取锁对象 RLock myLock = redissonClient.getLock("myLock"); try { // 2.准备锁代码,并进行加锁 myLock.lock(); // 进行图书的抢购,去库存 -1 } return num; } finally { // 3.解除锁 myLock.unlock(); // 把锁释放
<dependency>
<groupId>org.redissongroupId>
<artifactId>redisson-spring-boot-starterartifactId>
<version>3.9.1version>
dependency>
RedissonConfig.java
package com.tianju.springboot.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Bean // 别人写的对象,放到spring中
public RedissonClient redissonClient(){
Config config = new Config();
// "redis://192.168.198.130:6379"
config.useSingleServer().setAddress("redis://"+host+":6379");
return Redisson.create(config);
}
}
package com.tianju.redisDemo.service.impl;
import com.tianju.redisDemo.service.IBookService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class IBookServiceImpl implements IBookService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedissonClient redissonClient;
@Override
public Integer rushBuy(String key) {
// 1.获取锁对象
RLock myLock = redissonClient.getLock("myLock");
try {
// 2.准备锁代码,并进行加锁
myLock.lock();
// 进行图书的抢购,去库存 -1
String numStr = stringRedisTemplate.opsForValue().get(key);
if (numStr==null){
return null; // 商品剩余数量还没有进入缓存,不能抢购
}
int num = Integer.parseInt(numStr);
// 如果库存数量大于1;执行-1,去库存操作
if (num>0){
num--; // 去库存
// 更新当前库存数量
stringRedisTemplate.opsForValue().set(key, String.valueOf(num));
}
return num;
} finally {
// 3.解除锁
myLock.unlock(); // 把锁释放
}
}
}
1.Redis是线程安全的,但是高并发时出现数据不安全的问题;
2.解决办法,加锁,Redission分布式锁的使用;
3.Redis项目应用,图书的抢购,不加锁,数据不安全;
4.加了Redission中间件,保证原子性,数据安全;