28个案例问题分析---01---redis没有及时更新问题--Redis
创始人
2024-05-28 17:17:35

redis没有及时更新问题

  • 一:背景介绍
  • 二:前期准备
    • pom依赖
    • 连接Redis工具类
    • 连接mysql工具类
  • 三:过程
    • 使用redis缓存,缓存用户年龄
      • 业务对应流程图
      • 使用redis缓存用户年龄对应代码
  • 四:总结

一:背景介绍

在这里插入图片描述
业务中使用redis做缓存,来减少对数据库的操作,提升速度。使用的过程是
去redis内查询数据。如果有的话直接返回redis内的数据,如果没有的话去数据库查询数据,并将其存储到redis中,那么下次的查询就是在redis内查询的,省去了我们多次查询数据库的操作。
但是我们这个业务里,redis内存的数据可能与数据库的不一致。导致这种现象的原因是。在另外的业务中更改了数据库内的数据后,没有去修改redis内的数据,于是造成了redis数据与数据库数据不一致的问题。下面我就用一个小例子,演示上述问题,以及解决方案

二:前期准备

此实例是一个普通的maven项目。使用前需要准备好mysql数据,redis。具体方式大家可以上网查询。

pom依赖

项目连接mysql和redis,需要在maven内引入以下两个依赖.

    redis.clientsjedis3.3.0mysqlmysql-connector-java5.1.46

连接Redis工具类

编写一个连接Redis的工具类,这里直接使用的Jedis进行的连接。

/*** @BelongsProject: redis* @BelongsPackage: org.example.utils* @Author:hlzs1* @Description: redis的工具类* @CreateTime: 2023-03-03 20:42* @Version: 1.0*/
public class RedisUtils {public static Jedis jedis ;static {jedis = new Jedis("ip地址",6379,10000);//没有设置密码可以不填jedis.auth("000415");}/*** @description: 在redis取出数据* @author: haolizhuo* @date: 2023/3/4* @param: [key]* @return: java.lang.Object**/public  static Object redisGet(String key){return RedisUtils.jedis.get(key);}/*** @description:向redis存储数据* @author: haolizhuo* @date: 2023/3/4* @param: [key, value, seconds]* @return: void**/public static void redisSet(String key, String value, @Nullable Integer seconds){RedisUtils.jedis.set(key,value);if(seconds !=null){RedisUtils.jedis.expire(key,seconds);}}
}

连接mysql工具类

连接mysql需要对应的配置文件,新建一个jdbc.properties文件将此文件放到resources目录下即可

userName=root
password=deng123~
url=jdbc:mysql://ip地址/数据库名?useSSL=false&useUnicode=true&characterEncoding=utf8
driverClass=com.mysql.cj.jdbc.Driver

连接数据库的工具类

/*** @author : [haolizhuo]* @version : [v1.0]* @className : JDBCUtils* @description : [描述说明该类的功能]* @createTime : [2022/11/30 11:24]* @updateUser : [haolizhuo]* @updateTime : [2022/11/30 11:24]* @updateRemark : [描述说明本次修改内容]*/
public class JDBCUtils {private static String url;private static String userName;private static String password;private static String driverClass;private static Connection connection;static {try {Properties properties = new Properties();InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");properties.load(inputStream);driverClass = properties.getProperty("driverClass");url = properties.getProperty("url");userName = properties.getProperty("userName");password = properties.getProperty("password");} catch (Exception e) {e.printStackTrace();}}/** @version V1.0* Title: getConnection* @author haolizhuo* @description 获取数据库连接* @createTime  2022/11/30 11:36* @param []* @return java.sql.Connection*/public static Connection getConnection() {try {connection = DriverManager.getConnection(url, userName, password);} catch (Exception e) {e.printStackTrace();}return connection;}/** @version V1.0* Title: close* @author haolizhuo* @description 释放资源* @createTime  2022/11/30 11:39* @param [connection, statement, resultSet]* @return void*/public static void close(Connection connection, Statement statement, ResultSet resultSet) {if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}}

项目结构
在这里插入图片描述

到这里我们真个环境就准备好了,下面我们就复现背景里提到的,使用缓存的情况

三:过程

使用redis缓存,缓存用户年龄

这里是一个普通的使用redis的场景,我使用redis缓存了用户的年龄。key值是用户的id,value值是用户的年龄。

业务对应流程图

在这里插入图片描述

使用redis缓存用户年龄对应代码

    public static void main(String[] args) {//使用redis缓存,缓存某个id的用户的年龄,这里以1做示例String userId = "1";Object redisUserInfo = RedisUtils.redisGet(userId);//如果缓存查到信息,直接返回,并且结束if(null != redisUserInfo){System.out.println("redis获取到了用户"+userId+"的年龄,年龄为:" + redisUserInfo);return;}//缓存里没有就去数据库进行查询String sql ="select * from user_info where id = " + userId;Map userInfo = getUserInfo(sql);//如果查询到了信息,更新到缓存内if(userInfo != null){System.out.println("mysql获取到了用户"+userId+"的年龄,年龄为:" + userInfo.get("age"));RedisUtils.redisSet(userInfo.get("id").toString(),userInfo.get("age").toString(),60);}}/*** @description: 数据库查询用户数据* @author: haolizhuo* @date: 2023/3/4* @param: [sql]* @return: java.util.Map**/private static Map getUserInfo(String sql){Connection connection;Statement statement;ResultSet resultSet;Map map = new HashMap<>(16);try {//创建数据库连接connection = JDBCUtils.getConnection();statement = connection.createStatement();resultSet = statement.executeQuery(sql);//将值取出while (resultSet.next()){map.put("id",resultSet.getInt("id"));map.put("name",resultSet.getString("name"));map.put("age",resultSet.getInt("age"));}} catch (SQLException e) {throw new RuntimeException(e);}return map;}

这部分代码是没有问题,通过redis做了对应缓存。如果缓存过期了之后,就去数据库内查询,并且更新到缓存中。但是问题是,假设我们有别的业务更新了我们缓存的age数据,同时redis的数据没有过期,这是后就会造成一个数据不一致的问题。
执行代码,控制台打印
在这里插入图片描述
查看redis内数据
在这里插入图片描述
查看数据库内数据
在这里插入图片描述
现在我们的数据是正确无误,缓存与数据库数据一致。可如果我们的业务更新这个age的话,就会产生不一致的问题

    public static void main(String[] args) {String sql = "update user_info set age = 66 where id = 1";updateUserInfo(sql);}/*** @description: 数据库修改用户数据* @author: haolizhuo* @date: 2023/3/4* @param: [sql]* @return: void**/private static void updateUserInfo(String sql){Connection connection;Statement statement;int resultSet;try {//创建数据库连接connection = JDBCUtils.getConnection();statement = connection.createStatement();resultSet = statement.executeUpdate(sql);System.out.println(resultSet);} catch (SQLException e) {throw new RuntimeException(e);}}

更新完之后redis内数据
在这里插入图片描述
更新完之后数据库内数据
在这里插入图片描述
这时候,问题就暴露出来了,缓存数据与数据库数据不一致。并且缓存的数据还未过期。导致过期前查询的数据都不准确。
所以在使用缓存的时候,如果数据库内数据改了,一定要及时的
清空缓存!!!!清空缓存!!!!清空缓存!!!!

四:总结

这个问题的出现的根本原因是。不同的开发人员没有做好沟通,这两个业务是不同的人员编写的,没有考虑的业务的相关性,导致了这种问题的出现!!
所以不仅仅要实现功能也要考虑业务相关性!!!

相关内容

热门资讯

研报掘金丨浙商证券:维持吉祥航... 浙商证券研报指出,吉祥航空业绩修复节奏与行业略有不同,最差的时候已经过去,未来三年业绩修复斜率与利润...
苏奥传感跌2.01%,成交额9... 11月26日,苏奥传感盘中下跌2.01%,截至13:20,报8.78元/股,成交9762.93万元,...
中国动向公布中期业绩 公司拥有... .ct_hqimg {margin: 10px 0;} .hqimg_wrapper {text-a...
吉利汽车因雇员行使认股权而发行... .ct_hqimg {margin: 10px 0;} .hqimg_wrapper {text-a...
沪宁股份涨2.02%,成交额2... 11月26日,沪宁股份盘中上涨2.02%,截至13:24,报27.28元/股,成交2216.41万元...