Redis和数据库的结合
在实际的商用软件使用中,通常都是Redis和关系型数据配置使用,单纯使用Redis来存数据成本太高,并且其持久化和计算能力偏差,这两块无法和关系型数据相比较,而Redis和关系型数据库共存的场景就会带来另一个问题,就是在两者之间的数据一致性的问题,有太多的情况会导致Redis中的数据和关系型数据中的数据不一致,比如关系型数据库事务是完善的,Redis的事务没那么严格出现异常回滚,再比如Redis数据更新了但还没有像关系型数据库同步完成,再比如两个业务线的Redis都会同步关系型数据库数据,一边更新了而另一边就变成了脏数据等等
Redis和数据库读操作
从业务角度而言缓存不应该是永久的,这样极其容易造成脏数据的产生,而Redis也需要时进行垃圾回收给新数据腾出空间,因此一般来说应该加入一个超时时间,这样一旦数据超时,Redis就没法读出超时数据,这时候就会触发程序读取数据库,同步刷新缓存数据并设置超时时间,这样就完成了读操作,如下图所示
伪代码可以这样写
public DataObject readMethod(args){//尝试从Redis中读取数据DataObject data = getFromRedis(key);if (data != null){return data;}//从Redis读入不成功,从数据库中获取data = getFromDataBase();//写入RediswriteRedis(key, data);//设置key的超时时间为5分钟setRedisExprie(key,5);return data;
}
Redis和数据库写操作
写操作要考虑数据一致性的问题,所以首先应该从数据库中读取最新数据,然后对数据进行操作
写入数据是不能信任缓存的,从数据库中读取最新数据,然后进行业务操作,更新业务数据到数据库,再用新数据刷新Redis缓存,这样就完成了写操作,伪代码可以这样写
public DataObject writeMethod(args){//从数据库中读取最新数据DataObject dataObject = getFromDataBase(args);//执行业务逻辑execLogic(dataObject);//更新数据库数据updateDataBase(dataObject);//刷新缓存updateRedisData(key, dataObject);//设置超时时间setRedisExpire(key,5);
}
使用Spring的缓存机制整合Redis
首先建个项目的基本结构和必要基础数据,如下所示
<dependencies><!-- Spring核心包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring Bean包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring Context包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring Context支持包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring 表达式包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring面向切面(AOP)包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.2.1.RELEASE</version></dependency><!-- Spring JDBC包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.1.RELEASE</version></dependency><!-- dbcp2包 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>2.7.0</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.5</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.3</version></dependency><!-- MyBatis包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.3</version></dependency><!-- MySQL驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.29</version></dependency><!-- 实现slf4j接口并整合 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.26</version></dependency><!-- Spring Web 和 MVC --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.1.RELEASE</version></dependency><!-- POJO的验证 --><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.1.0.Final</version></dependency><!-- EXCEL --><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.1</version></dependency><dependency><groupId