②. 业务类、controller、service、entity、mapper
@Api(description = "用户User接口") @RestController @Slf4j public class UserController { @Resource private UserService userService; @ApiOperation("数据库新增5条记录") @RequestMapping(value = "/user/add",method = RequestMethod.POST) public void addUser() { for (int i = 1; i <=5; i++) { User user = new User(); user.setId(Integer.parseInt("100"+i)); user.setUsername("TANGZHI"+i); user.setPassword(IdUtil.simpleUUID().substring(0,6)); user.setSex((byte) new Random().nextInt(2)); user.setCreateTime(new Date()); userService.addUser(user); } } @ApiOperation("删除1条记录") @RequestMapping(value = "/user/delete/{id}",method = RequestMethod.POST) public void deleteUser(@PathVariable Integer id) { userService.deleteUser(id); } @ApiOperation("修改1条记录") @RequestMapping(value = "/user/update",method = RequestMethod.POST) public void updateUser(@RequestBody UserDTO userDTO) { User user = new User(); BeanUtils.copyProperties(userDTO,user); userService.updateUser(user); } @ApiOperation("查询1条记录") @RequestMapping(value = "/user/find/{id}",method = RequestMethod.GET) public User findUserById(@PathVariable Integer id) { return userService.findUserById(id); } }
@Service @Slf4j public class UserService { public static final String CACHE_KEY_USER = "user:"; @Resource private UserMapper userMapper; @Resource private RedisTemplate redisTemplate; //新增 public void addUser(User user) { //1 先插入mysql并成功 int i = userMapper.insertSelective(user); if(i > 0) { //2 需要再次查询一下mysql将数据捞回来并ok user = userMapper.selectByPrimaryKey(user.getId()); //3 将捞出来的user存进redis,完成新增功能的数据一致性。 String key = CACHE_KEY_USER+user.getId(); redisTemplate.opsForValue().set(key,user); } } //刪除 public void deleteUser(Integer id) { int i = userMapper.deleteByPrimaryKey(id); if(i > 0) { String key = CACHE_KEY_USER+id; redisTemplate.delete(key); } } //修改 public void updateUser(User user) { int i = userMapper.updateByPrimaryKeySelective(user); if(i > 0) { //2 需要再次查询一下mysql将数据捞回来并ok user = userMapper.selectByPrimaryKey(user.getId()); //3 将捞出来的user存进redis,完成修改 String key = CACHE_KEY_USER+user.getId(); redisTemplate.opsForValue().set(key,user); } } /** * 业务逻辑并没有写错,对于小厂中厂(QPS《=1000)可以使用,但是大厂不行 * @param id * @return */ public User findUserById(Integer id) { User user = null; String key = CACHE_KEY_USER+id; //1 先从redis里面查询,如果有直接1返回结果,如果没有再去查询mysql user = (User) redisTemplate.opsForValue().get(key); if(user == null) { //2 redis里面无,继续查询mysql user = userMapper.selectByPrimaryKey(id); if(user == null) { //3.1 redis+mysql 都无数据 //你具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redis return user; }else{ //3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率 redisTemplate.opsForValue().set(key,user); } } return user; } /** * 加强补充,避免突然key实现了,打爆mysql,做一下预防,尽量不出现击穿的情况。 * @param id * @return */ public User findUserById2(Integer id) { User user = null; String key = CACHE_KEY_USER+id; //1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql user = (User) redisTemplate.opsForValue().get(key); if(user == null) { //2 大厂用,对于高QPS的优化,进来就先加锁,保证一个请求操作,让外面的redis等待一下,避免击穿mysql synchronized (UserService.class){ user = (User) redisTemplate.opsForValue().get(key); //3 二次查redis还是null,可以去查mysql了(mysql默认有数据) if (user == null) { //4 查询mysql拿数据 user = userMapper.selectByPrimaryKey(id);//mysql有数据默认 if (user == null) { return null; }else{ //5 mysql里面有数据的,需要回写redis,完成数据一致性的同步工作 //setnx 不存在才创建 redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS); } } } } return user; } }