本篇博客开始进入到Redis的实例部分,基于springboot列举一些Redis的使用场景,同时针对不同的应用场景顺便复习一下springboot的一些操作。
构建一个springboot-redis的项目,并在这个项目下构建三个子模块
整体结构如下所示:
各个职责如下
springboot-redis-api——一些与H5交互的请求与返回体的定义
springboot-redis-model——持久层与数据访问层的一些实体与mapper
springboot-redis-server——主要业务的模块
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.learngroupId>
<artifactId>spring-boot-redisartifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<name>springboot中操作redis的相关应用场景name>
<url>https://blog.csdn.net/liman65727url>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
<maven.compiler.source>${java.version}maven.compiler.source>
<maven.compiler.target>${java.version}maven.compiler.target>
<spring-boot.version>2.2.2.RELEASEspring-boot.version>
<slf4j.version>1.7.13slf4j.version>
<log4j.version>1.2.17log4j.version>
<mysql.version>5.1.37mysql.version>
<mybatis-spring-boot.version>1.1.1mybatis-spring-boot.version>
<mybatis-pagehelper.version>5.1.4mybatis-pagehelper.version>
<druid.version>1.0.16druid.version>
<javax-validation.version>1.1.0.Finaljavax-validation.version>
<hibernate-validator.version>6.0.18.Finalhibernate-validator.version>
<guava.version>19.0guava.version>
<joda-time.version>2.9.2joda-time.version>
<retrofit.version>2.3.0retrofit.version>
<cglib.version>3.1cglib.version>
<resteasy.version>3.0.14.Finalresteasy.version>
<commons-beanutils.version>1.9.2commons-beanutils.version>
<redisson.version>3.8.2redisson.version>
<javamail.version>1.4.7javamail.version>
<lombok.version>1.16.10lombok.version>
properties>
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>${commons-beanutils.version}version>
dependency>
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>retrofitartifactId>
<version>${retrofit.version}version>
dependency>
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>converter-jacksonartifactId>
<version>${retrofit.version}version>
dependency>
<dependency>
<groupId>com.google.guavagroupId>
<artifactId>guavaartifactId>
<version>${guava.version}version>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>2.6.1version>
dependency>
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
<version>${joda-time.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>${spring-boot.version}version>
<exclusions>
<exclusion>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
exclusion>
<exclusion>
<groupId>org.slf4jgroupId>
<artifactId>log4j-over-slf4jartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-jasperartifactId>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
dependency>
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>${cglib.version}version>
<exclusions>
<exclusion>
<artifactId>asmartifactId>
<groupId>org.ow2.asmgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
<version>${spring-boot.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
<version>${spring-boot.version}version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-quartzartifactId>
<version>1.3.2version>
<exclusions>
<exclusion>
<groupId>org.opensymphony.quartzgroupId>
<artifactId>quartzartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>${redisson.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>4.6.10version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
<version>1.5.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>${mybatis-pagehelper.version}version>
dependency>
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>${javax-validation.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>${hibernate-validator.version}version>
dependency>
dependencies>
<repositories>
<repository>
<id>publicid>
<name>aliyun nexusname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<releases>
<enabled>trueenabled>
releases>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>publicid>
<name>aliyun nexusname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>falseenabled>
snapshots>
pluginRepository>
pluginRepositories>
<modules>
<module>springboot-redis-apimodule>
<module>springboot-redis-modelmodule>
<module>springboot-redis-servicemodule>
modules>
project>
<dependencies>
<dependency>
<groupId>com.learn.springboot-redis-modelgroupId>
<artifactId>springboot-redis-modelartifactId>
<version>${project.parent.version}version>
dependency>
dependencies>
所有的依赖均交给父pom去管理了,这里只需要引入我们需要的内部module就可以了,server需要依赖model的相关内容
<dependencies>
<dependency>
<groupId>com.learn.springboot-redis-apigroupId>
<artifactId>springboot-redis-apiartifactId>
<version>${project.parent.version}version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis-spring-boot.version}version>
dependency>
dependencies>
引入自己需要的mybatis
<dependencies>
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>${javax-validation.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>${hibernate-validator.version}version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>${mybatis-pagehelper.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
dependencies>
一些校验和分页的依赖。
执行如下SQL脚本,完成数据库的准备
CREATE DATABASE db_springboot_redis;
USE db_springboot_redis;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for item
-- ----------------------------
DROP TABLE IF EXISTS `item`;
CREATE TABLE `item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(255) DEFAULT NULL COMMENT '商品编号',
`name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '商品名称',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10012 DEFAULT CHARSET=utf8 COMMENT='商品信息表';
-- ----------------------------
-- Table structure for notice
-- ----------------------------
DROP TABLE IF EXISTS `notice`;
CREATE TABLE `notice` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '通告标题',
`content` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '内容',
`is_active` tinyint(4) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COMMENT='通告';
-- ----------------------------
-- Table structure for phone_fare
-- ----------------------------
DROP TABLE IF EXISTS `phone_fare`;
CREATE TABLE `phone_fare` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`phone` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '手机号码',
`fare` decimal(10,2) DEFAULT NULL COMMENT '充值金额',
`is_active` tinyint(4) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
PRIMARY KEY (`id`),
KEY `idx_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COMMENT='手机充值记录';
-- ----------------------------
-- Table structure for problem
-- ----------------------------
DROP TABLE IF EXISTS `problem`;
CREATE TABLE `problem` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(150) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '问题标题',
`choice_a` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项A',
`choice_b` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项B',
`is_active` tinyint(4) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
`order_by` tinyint(4) DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_title` (`title`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='问题库列表';
-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '商品名称',
`user_id` int(11) NOT NULL COMMENT '所属用户id',
`scan_total` int(255) DEFAULT NULL COMMENT '浏览量',
`is_active` tinyint(255) DEFAULT '1' COMMENT '是否有效',
PRIMARY KEY (`id`),
KEY `indx_scan_total` (`scan_total`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='商户商品表';
-- ----------------------------
-- Table structure for red_detail
-- ----------------------------
DROP TABLE IF EXISTS `red_detail`;
CREATE TABLE `red_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`record_id` int(11) NOT NULL COMMENT '红包记录id',
`amount` decimal(8,2) DEFAULT NULL COMMENT '每个小红包的金额(单位为分)',
`is_active` tinyint(4) DEFAULT '1',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=193 DEFAULT CHARSET=utf8 COMMENT='红包明细金额';
-- ----------------------------
-- Table structure for red_record
-- ----------------------------
DROP TABLE IF EXISTS `red_record`;
CREATE TABLE `red_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户id',
`red_packet` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '红包全局唯一标识串',
`total` int(11) NOT NULL COMMENT '人数',
`amount` decimal(10,2) DEFAULT NULL COMMENT '总金额(单位为分)',
`is_active` tinyint(4) DEFAULT '1',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT='发红包记录';
-- ----------------------------
-- Table structure for red_rob_record
-- ----------------------------
DROP TABLE IF EXISTS `red_rob_record`;
CREATE TABLE `red_rob_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL COMMENT '用户账号',
`red_packet` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '红包标识串',
`amount` decimal(8,2) DEFAULT NULL COMMENT '红包金额(单位为分)',
`rob_time` datetime DEFAULT NULL COMMENT '时间',
`is_active` tinyint(4) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=178 DEFAULT CHARSET=utf8 COMMENT='抢红包记录';
-- ----------------------------
-- Table structure for sys_config
-- ----------------------------
DROP TABLE IF EXISTS `sys_config`;
CREATE TABLE `sys_config` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典类型',
`name` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '字典名称',
`code` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项编码',
`value` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '选项取值',
`order_by` int(11) DEFAULT '1' COMMENT '排序',
`is_active` tinyint(4) DEFAULT '1' COMMENT '是否有效(1=是;0=否)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_type_code` (`type`,`code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='字典配置表';
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '姓名',
`email` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_email` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=52 DEFAULT CHARSET=utf8 COMMENT='用户表';
springboot的自动注入机制,使得我们集成第三方框架变得非常简单。
各位可以按照自己的喜好,集成druid,springboot自带的数据源等等等,这里我不打算采用springboot默认集成的数据源,也不打算采用druid第三方数据源组件,打算还是采用一个比较老的集成方式
建立一个spring-jdbc.xml文件,在里头完成数据源的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
" >
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" primary="true" >
<property name="url" value="${datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
<property name="initialSize" value="10" />
<property name="minIdle" value="10" />
<property name="maxActive" value="20" />
<property name="maxWait" value="60000" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 1 " />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
<property name="filters" value="stat" />
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
beans>
mybatis-config.xml
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="defaultStatementTimeout" value="3000"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="logImpl" value="stdout_logging" />
settings>
configuration>
#profile多环境配置 - 默认即为本配置文件
#spring.profiles.active=prod
#spring.profiles.active=test
#应用端口-应用上下文路径
server.port=8099
server.servlet.context-path=/redis
#前端模板引擎
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.suffix=.html
spring.freemarker.request-context-attribute=request
spring.freemarker.template-loader-path=classpath:/templates
#限定前端上传的文件大小
spring.servlet.multipart.max-request-size=20MB
spring.servlet.multipart.max-file-size=2MB
#日志级别
logging.level.org.springframework = INFO
logging.level.com.fasterxml.jackson = INFO
logging.level.com.learn.springboot = DEBUG
#json序列化配置
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.datasource.initialization-mode=never
spring.jmx.enabled=false
#数据源配置
datasource.url=jdbc:mysql://127.0.0.1:3306/db_springboot_redis?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
datasource.username=root
datasource.password=root
#mybatis
mybatis.config-location=classpath:mybatis-config.xml
mybatis.checkConfigLocation = true
mybatis.mapper-locations=classpath:mappers/*.xml
#redis 单机配置
spring.redis.host=192.168.72.128
spring.redis.port=6379
spring.redis.password=
spring.redis.jedis.pool.min-idle=100
spring.redis.jedis.pool.max-idle=300
spring.redis.jedis.pool.max-active=500
#集群配置
#spring.redis.cluster.nodes=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382
#通用配置
server.tomcat.additional-tld-skip-patterns=jaxb-api.jar,jaxb-core.jar
#spring java mail 发送邮件服务配置
spring.mail.host=smtp.qq.com
spring.mail.username=
spring.mail.password=
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
mail.send.from=
由于springboot自动注入的机制,我们只需要在properties文件中配置spring.redis的相关属性即可,集成Redis变成异常简单。
/**
* autor:liman
* createtime:2020/7/19
* comment:
*/
@Configuration
public class RedisConfg {
//springboot会为我们自动注入该工厂类
@Autowired
private RedisConnectionFactory redisConnectionFactory;
//配置RedisTemplate中的一些序列化策略
@Bean
public RedisTemplate redisTemplate(){
RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置序列化策略
redisTemplate.setKeySerializer(new StringRedisSerializer());//设置redis中key值的序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//设置redis中value值的序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());//设置haskKey值的序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
//配置StringRedisTemplate
@Bean
public StringRedisTemplate stringRedisTemplate(){
StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
return stringRedisTemplate;
}
}
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@SpringBootApplication
@ImportResource(value = {"classpath:spring/spring-jdbc.xml"}) //引入spring-jdbc.xml的配置
@MapperScan(basePackages = "com.learn.springboot.redis.model.mapper")//扫描mapper文件的路径配置
public class SpringBootRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRedisApplication.class,args);
}
}
这里我们以操作item实体来进行举例,Item实体可以看成是一个简单的商品实体,Item表对应简单的商品数据表。这里简单介绍商品实体的存取
package com.learn.springboot.redis.service.service.redis;
import com.learn.springboot.redis.service.constants.RedisKeyConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* autor:liman
* createtime:2020/7/26
* comment:操作string的Redisservice
*/
@Service
@Slf4j
public class StringRedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private ValueOperations getOperation(){
return stringRedisTemplate.opsForValue();
}
/**
* 设置key-value
* @param key
* @param value
* @throws Exception
*/
public void put(final String key,final String value) throws Exception{
getOperation().set(RedisKeyConstants.RedisStringPrefix+key,value);
}
/**
* 获取key-value
* @param key
* @return
* @throws Exception
*/
public Object get(final String key) throws Exception{
return getOperation().get(RedisKeyConstants.RedisStringPrefix+key);
}
/**
* 判断key-value是否存在
* @param key
* @return
* @throws Exception
*/
public Boolean exist(final String key) throws Exception{
return stringRedisTemplate.hasKey(RedisKeyConstants.RedisStringPrefix+key);
}
/**
* 设置指定的key-value过期时间
* @param key
* @param expireSeconds
* @throws Exception
*/
public void expire(final String key,final Long expireSeconds) throws Exception{
stringRedisTemplate.expire(key,expireSeconds, TimeUnit.SECONDS);
}
}
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@Service
@Slf4j
public class StringService {
private static final String KEY_PREFIX = "ITEM_";
@Autowired
private ItemMapper itemMapper;
@Autowired
private StringRedisService stringRedisService;
@Autowired
private ObjectMapper objectMapper;
/**
* 添加商品
* @param item
* @return
* @throws Exception
*/
@Transactional(rollbackFor = Exception.class)
public Integer addItem(Item item) throws Exception {
//先保存的数据库再保存的redis
item.setCreateTime(new Date());
item.setId(null);
itemMapper.insertSelective(item);
Integer id = item.getId();
//如果保存成功,这需要更新缓存
if(id>0){
stringRedisService.put(KEY_PREFIX+id.toString(),objectMapper.writeValueAsString(item));
}
return id;
}
/**
* 获取商品
* @param id
* @return
* @throws Exception
*/
public Item getItem(Integer id) throws Exception {
Item item = null;
if(id!=null){
//先取缓存中的数据
if(stringRedisService.exist(KEY_PREFIX+id.toString())){
String result=stringRedisService.get(id.toString()).toString();
log.info("---string数据类型,从缓存中取出来的value:{}---",result);
if(StrUtil.isNotBlank(result)){
item = objectMapper.readValue(result,Item.class);
}
}else{//如果缓存没有,则先从数据库区,取出之后并更新Redis
log.info("---string数据类型,从数据库查询:id={}---",id);
item=itemMapper.selectByPrimaryKey(id);
if (item!=null){
stringRedisService.put(KEY_PREFIX+id.toString(),objectMapper.writeValueAsString(item));
}
}
}
return item;
}
}
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@RestController
@Slf4j
@RequestMapping("string")
public class StringController {
@Autowired
private StringService stringService;
/**
* 添加商品
* @param item
* @param bindingResult
* @return
*/
@RequestMapping(value="put",method=RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public BaseResponse put(@RequestBody @Validated Item item,BindingResult bindingResult){
if(bindingResult.hasErrors()){
return new BaseResponse(StatusCode.InvalidParams);
}
BaseResponse response = new BaseResponse(StatusCode.Success);
try{
log.info("--添加商品信息:{}--",item);
stringService.addItem(item);
}catch (Exception e){
log.error("--字符串String实战-商品详情存储-添加-发生异常--:",e.fillInStackTrace());
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
@RequestMapping(value = "get",method = RequestMethod.GET)
public BaseResponse get(@RequestParam Integer prodId){
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
response.setData(stringService.getItem(prodId));
}catch (Exception e){
log.error("--Redis字符串String实战-商品详情存储-获取-发生异常:",e.fillInStackTrace());
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
}
List类型与String类型的操作大同小异,这里不再贴出全部代码,但是之前介绍过,list可以实现异步消息通知。
/**
* autor:liman
* createtime:2020/7/26
* comment:Redis 关于list 的操作
*/
@Slf4j
@Service
public class ListRedisService {
@Autowired
private RedisTemplate redisTemplate;
/**
* 将product 放入到Redis list中
* @param product
*/
public void pushRedisObject(final Product product){
ListOperations<String,Product> listOperations = redisTemplate.opsForList();
listOperations.leftPush(RedisKeyConstants.RedisListPrefix+product.getUserId(),product);
}
/**
* pop获取list中的object
* @param productKey
* @return
*/
public Product popRedisObject(final String productKey){
ListOperations<String,Product> listOperations = redisTemplate.opsForList();
Product product = listOperations.rightPop(productKey);
return product;
}
/**
* 获取Redis中存入的productList
* @param productKey
* @param reverse 是否倒序
* @return
*/
public List<Product> getRedisListObject(final String productKey,boolean reverse){
ListOperations<String,Product> listOperations = redisTemplate.opsForList();
List<Product> productList =Lists.newLinkedList();
productList = listOperations.range(productKey,0,listOperations.size(productKey));
if(!reverse){
return productList;
}else{
Collections.reverse(productList);
return productList;
}
}
/**
* 将一个数组批量压入到Redis中的list中。
* @param productKey
* @param productList
* @return
*/
public Long pushListIntoRedis(final String productKey,final List<Product> productList){
ListOperations<String,Product> listOperations = redisTemplate.opsForList();
Long aLong = listOperations.leftPushAll(productKey, productList);
return aLong;
}
}
/**
* autor:liman
* createtime:2020/7/26
* comment:List的业务Service
*/
@Slf4j
@Service
public class ListService {
@Autowired
private ListRedisService listRedisService;
@Autowired
private ProductMapper productMapper;
@Autowired
private NoticeMapper noticeMapper;
/**
* 添加商品
* @param product
* @return
*/
@Transactional(rollbackFor = Exception.class)
public Integer addProduct(Product product){
if(product!=null){
product.setId(null);
productMapper.insertSelective(product);
Integer id = product.getId();
if(id>0){
listRedisService.pushRedisObject(product);
}
return id;
}
return -1;
}
public List<Product> getHistoryProducts(final Integer userId){
log.info("=====开始查询productList:{}=====",userId);
List<Product> productList = Lists.newLinkedList();
final String productKey = RedisKeyConstants.RedisListPrefix+userId;
productList = listRedisService.getRedisListObject(productKey, false);
if(1>productList.size()){//如果缓存中没有则直接去数据库中取数据,并更新缓存
productList=productMapper.listProductsByUId(userId);
listRedisService.pushListIntoRedis(productKey,productList);//这种是List中只有一个元素,这个元素是一个list
}
log.info("=====查询的productList结果为:{}=====",productList);
return productList;
}
}
1、在ListController(完整代码没有贴出)中加入一个增加Notice的逻辑
//平台发送通知给到各位商户
@RequestMapping(value = "/notice/put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
public BaseResponse putNotice(@RequestBody @Validated Notice notice, BindingResult result){
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
log.info("--平台发送通知给到各位商户:{}",notice);
listService.pushNotice(notice);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
2、ListService中加入存入Notice的逻辑
/**
* 将需要发送的数据放入到redis队列缓存
* @param notice
*/
@Transactional(rollbackFor = Exception.class)
public void pushNotice(Notice notice){
if(notice!=null){
notice.setId(null);
noticeMapper.insertSelective(notice);
final Integer noticeId = notice.getId();
if(noticeId>0){//这里就将notice存入到Redis中
listRedisService.pushNoticeInRedis(notice);
}
}
}
将Notice存入到了Redis中之后,我们需要通过一个异步的批量操作,完成Redis中队列消息的处理,关于springboot启动批量任务,可以参考之前的博客 springboot开启定时任务。
3、开启定时任务的逻辑
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@Slf4j
@Component
@EnableScheduling
public class NoticeListenerScheduler {
private static final String noticeListenerKey = RedisKeyConstants.RedisListNoticeKey;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private UserMapper userMapper;
@Autowired
private EmailService emailService;
/**
批量任务的开启逻辑,循环消费list中的Notice实例
*/
@Scheduled(cron = "0/60 * * * * ?")
public void noticeListenerScheduler(){
log.info("=====定时任务开启,读取queue中的数据,并发送数据=====");
ListOperations<String,Notice> listOperations = redisTemplate.opsForList();
Notice notice = listOperations.rightPop(noticeListenerKey);
while(null!=notice){
log.info("======开始给指定商户:{}发送邮件=====");
this.noticeUser(notice);
notice = listOperations.rightPop(noticeListenerKey);
}
}
//发送通知给到不同的商户异步线程池
@Async("threadPoolTaskExecutor")
public void noticeUser(Notice notice){
if (notice!=null){
List<User> list=userMapper.selectList();
//TODO:写法一-java8 stream api触发
/*if (list!=null && !list.isEmpty()){
list.forEach(user -> emailService.emailUserNotice(notice,user));
}*/
//TODO:写法二-线程池/多线程触发
try {
if (list!=null && !list.isEmpty()){
ExecutorService executorService=Executors.newFixedThreadPool(4);
List<NoticeThread> threads= Lists.newLinkedList();
list.forEach(user -> {
threads.add(new NoticeThread(user,notice,emailService));
});
executorService.invokeAll(threads);
}
}catch (Exception e){
log.error("近实时的定时任务检测-发送通知给到不同的商户-法二-线程池/多线程触发-发生异常:",e.fillInStackTrace());
}
}
}
}
4、加入线程池的配置
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@Configuration
@Slf4j
public class ThreadPoolConfig {
@Bean("threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setKeepAliveSeconds(10);
executor.setQueueCapacity(8);
//设置的拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
别忘了,主类中需要加上异步和批量的注解
/**
* autor:liman
* createtime:2020/7/26
* comment:
*/
@SpringBootApplication
@ImportResource(value = {"classpath:spring/spring-jdbc.xml"})
@MapperScan(basePackages = "com.learn.springboot.redis.model.mapper")
@EnableScheduling
@EnableAsync
public class SpringBootRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRedisApplication.class,args);
}
}
本篇博客由于篇幅所限,主要介绍了项目创建于集成的工作,目前只能介绍到String与List类型的基本操作。