使用springboot实现redis作为mysql缓存

  • 前言
  • 项目代码
    • 配置文件
    • 代码示例

前言

例子在github上使用springboot实现redis作为mysql缓存.
因为博主的linux通过购买阿里服务器并使用宝塔linux系统,博主通过宝塔系统提供的软件商店下载的Mysql和Redis。通过命令行安装网络上已经有很多,这里就不在赘述。

不过,大同小异之处在一下两点。
1. 开放3306和6379端口。可以在windows端使用telnet 服务器ip地址 端口号来检测服务器中是否开启该端口号,如下图:

端口号若开启,则会出现如下图所示

2. 修改mysql的host为*,因为默认的host为127.0.0.1,只能被本地访问
修改redis的配置文件,bind 0.0.0.0、daemonize yes
使用navicat测试mysql是否能够被连接,使用RedisDesktopManager测试redis是否能够被连接
使用redis缓存注意点
1.数据读频率远远高于写频率时使用redis作为缓存可以大大提高读数据的效率。
2.数据写频率远远高于读频率时不适合使用redis作为缓存,或者说不应该设计缓存。因为每次往数据库写数据时都会更新缓存。
需要根据自己的业务场景来选择是否需要设计缓存

项目代码

配置文件

新建application-local.yml作为本地配置,并在系统生成的application.properties中加上

spring.profiles.active=local

表示启用application-local中的配置。一般,这个配置是作为本地测试时使用的配置。生产环境的配置文件名为application-prod.yml,该配置是生产环境的配置。

application-local.yml

# server config
server:port: 8085max-http-header-size: 8192
# spring config
spring:datasource:
#    数据库连接name: ssm_demo_redisurl: jdbc:mysql://yourhostip/ssm_demo_redisusername: rootpassword: password
#    使用druid数据源type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driver
#    数据源配置dbcp2:initial-size: 2minIdle: 5max-total: 20max-wait-millis: 60000time-between-eviction-runs-millis: 60000soft-min-evictable-idle-time-millis: 300000validation-query: SELECT 1test-while-idle: truetest-on-borrow: falsepool-prepared-statements: falsemax-open-prepared-statements: 20# 时区设置为东八区jackson:time-zone: GMT+8redis:database: 0 # Redis 数据库索引(默认为 0)host: your host ip # Redis 服务器地址port: 6379 # Redis 服务器连接端口password: password # Redis 服务器连接密码(默认为空)lettuce:pool:max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1max-idle: 8 # 连接池中的最大空闲连接 默认 8min-idle: 0 # 连接池中的最小空闲连接 默认 0cache:type: redisredis:cache-null-values: true  # Allow caching null values.key-prefix: # Key prefix.time-to-live: # 缓存到期时间,默认不主动删除永远不到期use-key-prefix: true  # Whether to use the key prefix when writing to Redis.# MyBatis Configure
mybatis:mapperLocations: classpath:mapper/*.xmltypeAliasesPackage: com.tencent.tusi.springboot_demo_redis_mybatis.entity
  1. 配置端口与Tomcat的HTTP请求头缓冲区大小,因为springboot内置tomcat,在这里配置,启动项目时会读取该配置到tomcat中。
  2. 配置mysql数据源,注意点:使用druid数据源的时候,其中driver-class-name应该根据mysql版本来选择,本项目使用的是com.mysql.cj.jdbc.Driver,网上说使用6及以上的版本,不太清除我的mysql版本是5.5.62也需要使用该驱动。
  3. 配置redis连接以及连接池,因为博主的redis版本是5.0.5,所以连接池使用的是lettuce,这里面要注意的是在pom中需要加入
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
  1. 配置项目使用redis作为缓存,并在启动类中加上@EnableCaching注解。不加的话springboot是启用默认的缓存
  2. 配置mybatis的mapper和实体类信息,并在启动类中加上@MapperScan(“com.tencent.tusi.springboot_demo_redis_mybatis.dao”),用于扫描到该包下的接口对应mapper。

pom.xml
在依赖文件中有几个重要的依赖包

  1. mysql连接依赖:
<!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>
  1. 使用mybatis的相关依赖
<!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency>
  1. 使用redis作为缓存的依赖
<!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
  1. 使用lombok插件,简化开发。在实体类上加上@Data注解自动生成getter/setter方法以及toString()方法等
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

代码示例

redis配置信息

/** Copyright © 1998 - 2018 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/*** @author shanpeng*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(redisConnectionFactory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);}
}

因为redis存储的键值对是通过StringRedisTemplate来存储的,但是值只有String类型,但是实际生产中大多数都是使用对象。虽然redis也支持存储对象,其思路是先对对象进行序列化,默认使用的是JdkSerializationRedisSerializer对pojo进行序列化,然后保存二进制数据到redis数据库中,但是此时使用RedisDesktopManager来查看数据时,因为是二进制数据,所以无法直观的看到到底写进来的是什么。
当前思路是改变默认的序列化方法,使用Jackson2JsonRedisSerializer将pojo保存为JSON数据存储在数据库中,一者,这种方式效率很高,另外,这种方式也解决了乱码问题。关键还是这四行代码,指定了redis以何种方式存储键值对

redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

这一步直接写进redis数据库是没有问题的,但是redis作为缓存,功能实现还不够完整,所以需要下面的代码块,配置缓存的序列化和redisTemplate保持一致,因为上面已经配置了setXXX,这里只要通过redisTemplate.getValueSerializer()就可以获取到redisTemplate中值的序列化方式,并通过RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith()来设置redis缓存默认的序列化方式
实体类信息

/** Copyright © 1998 - 2020 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.entity;import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** @author shanpeng*/
@Data
public class AccountInfo implements Serializable {private static final long serialVersionUID = -1340095119555693650L;public AccountInfo() {}private int id;private String accountName;private String accountAge;private String nickName;private String password;private Date createTime;private Date updateTime;
}

因为要缓存数据之前,要对数据进行序列化,所以该实体类实现了Serializable 接口,并通过IDEA自动生成序列ID,如何配置可以自行搜索步骤,关键点在这:
AccountInfoDao

/** Copyright © 1998 - 2018 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.dao;import com.tencent.tusi.springboot_demo_redis_mybatis.entity.AccountInfo;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Qualifier;import java.util.List;/*** @author shanpeng*/
@Qualifier(value = "accountDao")
public interface AccountInfoDao {int saveAccountInfo(@Param("pojo")AccountInfo accountInfo);int removeAccountById(@Param("id")int id);AccountInfo findAccountInfoById(@Param("id")int id);int updateAccountInfo(@Param("pojo")AccountInfo accountInfo);List<AccountInfo> findAllAccountInfo();
}

包含了常用的增删查改。

AccountInfoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tencent.tusi.springboot_demo_redis_mybatis.dao.AccountInfoDao"><resultMap id="allColumns" type="com.tencent.tusi.springboot_demo_redis_mybatis.entity.AccountInfo"><id column="id" property="id"/><result column="c_name" property="accountName"/><result column="c_age" property="accountAge"/><result column="c_nickname" property="nickName"/><result column="c_password" property="password"/><result column="createtime" property="createTime"/><result column="updatetime" property="updateTime"/></resultMap><insert id="saveAccountInfo" useGeneratedKeys="true" keyProperty="id">insert into t_account<trim prefix="(" suffix=")" suffixOverrides=","><if test="pojo.accountName != null and pojo.accountName != ''">c_name,</if><if test="pojo.accountAge != null and pojo.accountAge != 0">c_age,</if><if test="pojo.nickName != null and pojo.nickName != ''">c_nickname,</if><if test="pojo.password != null and pojo.password != ''">c_password,</if>createtime,updatetime</trim>values<trim prefix="(" suffix=")" suffixOverrides=","><if test="pojo.accountName != null and pojo.accountName != ''">#{pojo.accountName},</if><if test="pojo.accountAge != null and pojo.accountAge != 0">#{pojo.accountAge},</if><if test="pojo.nickName != null and pojo.nickName != ''">#{pojo.nickName},</if><if test="pojo.password != null and pojo.password != ''">#{pojo.password},</if>now(),now()</trim></insert><update id="updateAccountInfo">update t_account<set><if test="pojo.accountName != null and pojo.accountName != ''">c_name = #{pojo.accountName},</if><if test="pojo.accountAge != null and pojo.accountAge != 0">c_age = #{pojo.accountAge},</if><if test="pojo.nickName != null and pojo.nickName != ''">c_nickname = #{pojo.nickName},</if><if test="pojo.password != null and pojo.password != 0">c_password = #{pojo.password},</if>updatetime = now()</set>where id = #{pojo.id}</update><delete id="removeAccountById">delete from t_accountwhere id = #{io}</delete><select id="findAccountInfoById" resultMap="allColumns">select * from t_accountwhere id = #{id}</select><select id="findAllAccountInfo" resultMap="allColumns">select * from t_account</select>
</mapper>

与dao对应,具体的sql语句。
service接口

/** Copyright © 1998 - 2018 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.service.service;import com.tencent.tusi.springboot_demo_redis_mybatis.entity.AccountInfo;import java.util.List;/*** @author shanpeng*/
public interface AccountInfoService {int saveAccountInfo(AccountInfo accountInfo);int removeAccountInfoById(int id);AccountInfo findAccountInfoById(int id);int updateAccountInfo(AccountInfo accountInfo);List<AccountInfo> findAllAccountInfo();
}

service层接口实现类

/** Copyright © 1998 - 2018 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.service.impl;import com.tencent.tusi.springboot_demo_redis_mybatis.dao.AccountInfoDao;
import com.tencent.tusi.springboot_demo_redis_mybatis.entity.AccountInfo;
import com.tencent.tusi.springboot_demo_redis_mybatis.service.service.AccountInfoService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;/*** @author shanpeng*/
@Service
public class AccountInfoServiceImpl implements AccountInfoService {@ResourceAccountInfoDao accountInfoDao;@Override@Caching(evict = {@CacheEvict(cacheNames = "accountList",allEntries = true)},put = {@CachePut(cacheNames = "account",key = "#accountInfo.id")})public int saveAccountInfo(AccountInfo accountInfo) {return accountInfoDao.saveAccountInfo(accountInfo);}@Override@Caching(evict = {@CacheEvict(cacheNames = "accountList",allEntries = true),@CacheEvict(cacheNames = "account",key = "#id")})public int removeAccountInfoById(int id) {return accountInfoDao.removeAccountById(id);}@Override@Cacheable(value = "account")public AccountInfo findAccountInfoById(int id) {return accountInfoDao.findAccountInfoById(id);}@Override@Cacheable(value = "accountList")public List<AccountInfo> findAllAccountInfo(){return accountInfoDao.findAllAccountInfo();}@Override@Caching(evict = {@CacheEvict(cacheNames = "accountList",allEntries = true)},put = {@CachePut(cacheNames = "account",key = "#accountInfo.id")})public int updateAccountInfo(AccountInfo accountInfo) {return accountInfoDao.updateAccountInfo(accountInfo);}
}

几个注意点:
1. 使用@Resource注入,试过使用@Autowired以及结合使用@Qualifier,无法注入。在SSM框架中使用@Autowied可以注入dao。
2. 查找数据时,使用@Cacheable注解,并指定它的名称。下图是我运行项目后redis数据库中的信息。再次查找数据时,会通过value到redis中查找并返回,如果没有数据则会直接到mysql数据库中查找。

3. 删除数据时的思路,先删除数据库里面的信息,再删除对应的缓存信息,如果缓存信息删除失败,则回滚数据库。使用@CacheEvict注解,通过cacheNames 值删除对应的缓存。
4. 更新时,根据需求删除缓存,或者是更新缓存。更新缓存的注解是@CachePut,这里面指定的cacheNames 是根据名称找到缓存值,key是根据key值来更新它所对应的缓存值。
控制层(Controller)

/** Copyright © 1998 - 2018 Tencent. All Rights Reserved* www.tencent.com* All rights reserved.*/
package com.tencent.tusi.springboot_demo_redis_mybatis.controller;import com.tencent.tusi.springboot_demo_redis_mybatis.entity.AccountInfo;
import com.tencent.tusi.springboot_demo_redis_mybatis.service.service.AccountInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** @author shanpeng*/
@Controller
@RequestMapping(value = "demo")
public class AccountInfoController {@AutowiredAccountInfoService accountInfoService;@PostMapping(value = "/saveAccount")@ResponseBodypublic int saveAccount(@RequestBody AccountInfo accountInfo){return accountInfoService.saveAccountInfo(accountInfo);}@GetMapping(value = "/getAccount/{id}")@ResponseBodypublic AccountInfo findAccount(@PathVariable(value = "id")int id){return accountInfoService.findAccountInfoById(id);}@GetMapping(value = "/getAllAccount")@ResponseBodypublic List<AccountInfo> findAllAccount(){return accountInfoService.findAllAccountInfo();}@RequestMapping(value = "/removeAccount/{id}",method = RequestMethod.DELETE)@ResponseBodypublic int removeAccountById(@PathVariable("id")int id){return accountInfoService.removeAccountInfoById(id);}@RequestMapping(value = "/updateAccount",method = RequestMethod.PUT)@ResponseBodypublic int updateAccount(@RequestBody AccountInfo accountInfo){return accountInfoService.updateAccountInfo(accountInfo);}
}

这里只是用于使用POSTMAN测试用的,并没有什么细节信息。该接口并未符合Restful风格。

使用springboot实现redis作为mysql缓存相关推荐

  1. springboot和redis处理页面缓存

    页面缓存是应对高并发的一个比较常见的方案,当请求页面的时候,会先查询redis缓存中是否存在,若存在则直接从缓存中返回页面,否则会通过代码逻辑去渲染页面,并将渲染后的页面缓存到redis中,然后返回. ...

  2. 8分钟带你学会SpringBoot整合Redis来实现缓存技术

    1.概述 随着互联网技术的发展,对技术要求也越来越高,所以在当期情况下项目的开发中对数据访问的效率也有了很高的要求,所以在项目开发中缓存技术使用的也越来越多,因为它可以极大的提高系统的访问速度,关于缓 ...

  3. redis配置mysql缓存_Redis做mysql的缓存服务器

    一redis简介:redis 是一个高性能的 key-value 数据库. redis 的出现,很大程度补偿了memcached 这类 keyvalue 存储的不足,在部分场合可以对关系数据库起到很好 ...

  4. [Springboot]SpringCache + Redis实现数据缓存

    前言 本文实现了SpringCache + Redis的集中式缓存,方便大家对学习了解缓存的使用. 本文实现: SpringCache + Redis的组合 通过配置文件实现了自定义key过期时间:k ...

  5. SpringBoot+Caffeine+Redis声明式缓存

    目录 [博客目的] [应用场景] [相关知识] [代码实践] 引入组件 配置文件 配置类 启动类 业务层 实体类 接口层 [博客目的] 记录一个项目中同时整合了Caffeine和Redis时,怎么使用 ...

  6. 怎样将redis写入mysql_使用redis做mysql缓存

    应用Redis实现数据的读写,同时利用队列处理器定时将数据写入mysql. 同时要注意避免冲突,在redis启动时去mysql读取所有表键值存入redis中,往redis写数据时,对redis主键自增 ...

  7. redis写入mysql 使用redis做mysql缓存

    应用Redis实现数据的读写,同时利用队列处理器定时将数据写入mysql. 同时要注意避免冲突,在redis启动时去mysql读取所有表键值存入redis中,往redis写数据时,对redis主键自增 ...

  8. 部署Redis作为mysql缓存实现读写分离

    1. redis+mysql缓存服务器实现读写分离 Redis其实就是说把表中经常访问的记录放在了Redis中,然后用户查询时先去查询Redis再去查询MySQL,确实实现了读写分离,也就是Redis ...

  9. Redis作为MySQL缓存服务器的使用

    server1:192.168.1.11  安装nginx和php为用户提供服务访问入口 server3:192.168.1.13  安装mysql,存储数据 server2:192.168.1.12 ...

  10. redis做mysql缓存的优点_面试官:如何保障数据库和redis缓存的一致性

    随着互联网的高速发展,使用互联网产品的人也越来越多,团队不可避免得也会面对越来越复杂的高并发业务场景(如下图),比如热点视频/文章的观看(读场景),热点视频/文章的评论,点赞等(写场景). 众所周知, ...

最新文章

  1. 跟随一笔交易来看以太坊c++客户端源码执行流程 / 源码分析
  2. 一次DB2数据库连接失败(SQLSTATE=08001)的解决方法
  3. Tomcat下项目调整Log4J的console输出级别,减少输出信息
  4. [转载] 杜拉拉升职记——07 管理者关心细节吗?
  5. 线性代数中的矩阵消元法,求逆
  6. secureCRT回滚行数
  7. Qt_发送邮件(以qq邮箱为例)
  8. 运行 lighttrack 遇到错误和解决方法
  9. SVM分类器(matlab)
  10. 以观察者设计模式举例的房产信息系统
  11. Spring Boot 接入支付宝完整流程实战,看完后秒懂!
  12. MySQL数据文件的组织
  13. LabVIEW 编程小技巧
  14. 电脑右下角音量键打不开,调不了音量大小的解决方法
  15. python设计报告的前言怎么写_前  言_Python语言程序设计_红黑联盟读书频道
  16. 计算机操作者权限恢复,win10系统提示“需要管理员权限”的还原方案
  17. WIN7 嵌入式系统安装教程 Windows Embedded Standard 2011 安装
  18. PeckShield:图文拆解FCoin资产流向,其鼎盛时期便已显颓势?
  19. 如何优化网站,网站推广优化一般流程
  20. 河南自考本科计算机相关专业,速看,河南自考本科计算机及应用专业介绍

热门文章

  1. 超级鸡马虚拟服务器,超级鸡马按键操作图文教程_超级鸡马怎么玩_牛游戏网
  2. 30本从禁书到名著的阅读书单
  3. win2012服务器 注册表,第十一章 Windows Server 2012 R2 注册表域注册表编辑器 ---学习笔记...
  4. phP imageMagic抠图,使用 Lua + ImageMagick 轻松批量抠图
  5. JS 关于事件冒泡,事件捕获,阻止事件冒泡,取消默认事件
  6. D2 日报 2019年 03月 13日
  7. UIkit之滚动监听+动画特效
  8. 使用逻辑回归对信用卡诈骗分析
  9. 常见的计算机查询语言,利用SQL语句查询SCCM常用报表
  10. 监控mysql锁定状态_mysql InnoDB锁等待的查看及分析