1.缓存
当执行增删改操作时,必须保证缓存和数据库一致性。
/**
* 添加数据
* @param dept 添加数据信息
* @return
*/
@Override
public Integer insertData(Dept dept) {
int insert = deptMapper.insert(dept);
return insert;
}
/**
* 修改数据
* @param dept 修改数据信息
* @return
*/
@Override
public Integer updateData(Dept dept) {
//修改数据库前 删除缓存数据 让缓存和数据库保持一致
redisTemplate.delete("dept::" + dept.getId());
int i = deptMapper.updateById(dept);
return i;
}
/**
* 删除数据
* @param id 根据id删除数据
* @return
*/
@Override
public Integer deleteData(Integer id) {
//删除数据库前 删除缓存数据 让缓存和数据库保持一致
redisTemplate.delete("dept::"+id);
return deptMapper.deleteById(id);
}
2.redis使用分布式锁
(1)通过使用jmter压测工具测试
同一个库存被多个线程卖,线程安全问题。
可以使用锁解决: ---synchronized和Lock锁
public String jianStock(Integer pid){
try {
lock.lock();//加锁
// 1. 查询指定的商品库存
Stock stock = stockDao.selectById(pid);
if (stock.getNum() > 0) {
//2.库存减1
stock.setNum(stock.getNum() - 1);
stockDao.updateById(stock);
System.out.println("库存剩余数量:" + stock.getNum());
return "减库存成功";
} else {
System.out.println("库存不足");
return "库存减失败";
}
}
finally {
lock.unlock(); //释放锁
}
}
上面的synchronized或Lock锁不适合集群模式|分布式系统。、因为synchronized都是基于JVM的本地锁。
需要在idea中跑项目的集群
配置nginx
启动nginx
任务管理器查看是否开启
jmeter压测
两台集群出现了重卖问题。
2.2使用redis来解决--分布式锁
//分布式锁 存在超时问题
public String jianStock(Integer pid){
//占锁
ValueOperations<String, String> forValue = redisTemplate.opsForValue();
//占锁失败
while (!forValue.setIfAbsent("product::" + pid,"",30,TimeUnit.SECONDS)){
try {
Thread.sleep(30);
}catch (Exception e){
e.printStackTrace();
}
}
//占锁成功
//1.查询指定的商品库存
try {
Stock stock = stockDao.selectById(pid);
if(stock.getNum() > 0){
//2.库存减一
stock.setNum(stock.getNum() - 1);
stockDao.updateById(stock);
System.out.println("库存剩余数量:"+ stock.getNum());
return "减库存成功";
}else {
System.out.println("库存不足");
return "减库存失败";
}
}finally {
//释放锁资源
redisTemplate.delete("product::" + pid);
}
}
分布式锁可以解决集群重卖问题。
但是会出现超时问题:如果你的业务代码的执行时间超过30s,当前线程删除的是其他线程的锁资源。
解决超时问题使用 -- watchDog机制
每隔10s检测当前线程是否还持有锁资源,如果持有则为当前线程延迟。 -- 可以自己设置watchDog机制, --- 可以使用Redission第三方组件完美的解决分布式锁超时问题。
2.3redisson完美解决redis超时问题
导入redisson依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
(2)配置redisson类
@Bean //创建redisson交于spring容器来管理
public RedissonClient redisson() {
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.223.166:6379");
RedissonClient redisson = Redisson.create(config);
return redisson;
}
(3) 使用
//分布式锁 使用watch dog机制 如果还持有锁,延长生存时间 解决超时问题
public String jianStock(Integer pid){
RLock lock = redissonClient.getLock("product::" + pid); //获取锁
try {
lock.lock(30,TimeUnit.SECONDS);//加锁:如果程序执行时出现异常
//1.查看指定商品库存
Stock stock = stockDao.selectById(pid);
//2.减库存
if(stock.getNum() > 0){
stock.setNum (stock.getNum() -1);
stockDao.updateById(stock);
System.out.println("库存剩余数量:" + stock.getNum());
return "减库存成功";
}else {
System.out.println("库存不足");
return "减库存失败";
}
}finally {
lock.unlock();
}
}