测试类
Springsecurityday01ApplicationTests.java
package com.x.springsecurityday01;
import com.alibaba.fastjson.JSON;
import com.x.springsecurityday01.dao.MenuDao;
import com.x.springsecurityday01.dao.UserDao;
import com.x.springsecurityday01.domain.Menus;
import com.x.springsecurityday01.domain.Users;
import com.x.springsecurityday01.domain.vo.MenusTreeVo;
import com.x.springsecurityday01.util.Count;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class Springsecurityday01ApplicationTests {
@Autowired(required = false)
private RedisTemplate<String,String> redisTemplate;
@Autowired
private Count counter;
@Test
void testLock() throws InterruptedException {
/**
* 创建一个子线程
*/
Thread thread1 = new Thread(() -> {
for (int i = 0; i< 5000;i++){
counter.sub();
}
});
Thread thread2 = new Thread(() -> {
for (int i =0; i< 5000;i++){
counter.sub();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter.count);
}
/**
* 怎么用redis实现分布锁
* 1.利用redis单线程特性
* 2:setIfAbsent(,):
* 作用1:可以放一个key,value到redis;
* 作用2:会根据key查redis数据库有没有,没有返回true,有返回false
*
*/
@Test
void testRedis2(){
}
/**
* 操作redis list数据类型
*/
@Test
void testRedisList(){
ListOperations<String, String> list = redisTemplate.opsForList();
// list.leftPush("list","hello1");
// list.leftPush("list","hello2");
// list.leftPush("list","hello3");
// String list1 = list.leftPop("list");//消费
// System.out.println(list1);
List<String> list2 = list.range("list", 0, 2);
for(String s:list2){
System.out.println(s);
}
}
/**
* 操作redis set数据类型
*/
@Test
void testRedisSet(){
SetOperations<String, String> set = redisTemplate.opsForSet();
set.add("set","hello1");
set.add("set","hello2");
set.add("set","hello3");
Set<String> set1 = set.members("set");
for (String s : set1) {
System.out.println(s);
}
}
}
Count.java
package com.x.springsecurityday01.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class Count {
//第一种写法把当前线程id 传进入
//第二种写法 uuid
/**
* 取钱的功能
*/
public int count = 10000;
@Autowired
private StringRedisTemplate redisTemplate;
public void sub(){
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123",5, TimeUnit.SECONDS);
try {
if(lock){
if(count > 0){
this.count --;
//1:先查count 原来值
//2:减一
//3:赋值
}
}else {
sub();//自旋锁
}
} catch (Exception e) {
e.printStackTrace();
}finally {
redisTemplate.delete("lock");
}
}
}
UserSErviceImpl.java
package com.woniu.springsecurityday01.service.impl;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniu.springsecurityday01.dao.MenuDao;
import com.woniu.springsecurityday01.dao.UserDao;
import com.woniu.springsecurityday01.domain.Menus;
import com.woniu.springsecurityday01.domain.Users;
import com.woniu.springsecurityday01.domain.vo.MenusTreeVo;
import com.woniu.springsecurityday01.service.UserService;
import com.woniu.springsecurityday01.util.RequestParams;
import com.woniu.springsecurityday01.util.ResponseResult;
import lombok.AllArgsConstructor;
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;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Service
public class UserSErviceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private MenuDao menuDao;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 查询用户菜单
* 缓存一致性问题?出现缓存不一致的原因:因为对原始数据做变更了(增删改)
* 解决方案;
* 1:数据库改了,缓存也改(不采用修改缓存的方案)
* 2:对原始数据(增删改)操作,删除缓存
*
* @param account
* @return
*/
@Override
public ResponseResult<?> queryMenusByUser(String account) {
String userStr = redisTemplate.opsForValue().get("menu:" + account);
//redis是否有缓存数据
if(userStr!=null||"".equals(userStr)){
List<Menus> menus = JSON.parseArray(userStr, Menus.class);
List<Menus> menuNode = getMenuNode(menus);
return new ResponseResult<>().ok(menuNode);
}else {
//缓存没有,查数据,并且把数据库数据缓存到redis
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("lock", "lock", 5, TimeUnit.SECONDS);
try {//解决缓存击穿
if(aBoolean){
//拿到锁
List<Menus> menus = menuDao.queryMenusByAccount(account);
//解决缓存穿透
if(menus==null){
redisTemplate.opsForValue().set("menu"+account,"");
}else {
redisTemplate.opsForValue().set("menu"+account,JSON.toJSONString(menus));
}
List<Menus> menuNode = getMenuNode(menus);
return new ResponseResult<>().ok(menuNode);
}else {
return new ResponseResult<>().ok("系统繁忙");
}
} catch (Exception e) {
e.printStackTrace();
return new ResponseResult<>().fail();
}finally {
redisTemplate.delete("lock");
}
}
}
// @Override备份
// public ResponseResult<?> queryMenusByUser(String account) {
//
// String userStr = redisTemplate.opsForValue().get("menu:" + account);
// //redis是否有缓存数据
// if(userStr!=null||"".equals(userStr)){
// List<Menus> menus = JSON.parseArray(userStr, Menus.class);
// List<Menus> menuNode = getMenuNode(menus);
// return new ResponseResult<>().ok(menuNode);
// }else {
// //缓存没有,查数据,并且把数据库数据缓存到redis
// List<Menus> menus = menuDao.queryMenusByAccount(account);
// //解决缓存穿透
// if(menus==null){
// redisTemplate.opsForValue().set("menu"+account,"");
// }else {
// redisTemplate.opsForValue().set("menu"+account,JSON.toJSONString(menus));
// }
// List<Menus> menuNode = getMenuNode(menus);
// return new ResponseResult<>().ok(menuNode);
// }
//
//
//
// }
/**
* 把菜单封装成树形结构
* @param menus
* @return
*/
public List<Menus> getMenuNode(List<Menus> menus ){
//找到所有的一级菜单
List<Menus> parentMenus = menus.stream().filter(e -> e.getParentId() == null)
.collect(Collectors.toList());
for(Menus parentMenu :parentMenus){
List<Menus> childrenMenus=new ArrayList<>();
for(Menus menu:menus){
//找出一级菜单对应二级菜单
if(parentMenu.getId().equals(menu.getParentId())){
//
childrenMenus.add(menu);
}
}
parentMenu.setChildrenMenu(childrenMenus);
}
return parentMenus;
}
}