开发者学堂课程【使用 Redis 消息队列完成秒杀过期订单处理 :借助 redis 的 key 失效通知设置优惠券状态】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/729/detail/13022
借助 redis 的 key 失效通知设置优惠券状态
内容介绍
一.配置监听 redis 的通知
1. 定义一个消息的监听器
2.将监听类配置到 Spring 配置文件中去
3.编写测试
一、配置监听 redis 的通知
Coupon-achieve 中创建好了一张优惠券,并且存入到数据库,同时再 redis 设置了其失效时间后,在第二个程序 coupon-expired 中配置监听器,去监听 reids 失效 key 的通知,在其中配置或监听 redis 的通知操作步骤为两步:
1.定义一个消息的监听器
在 listener 包下创建一个 RedisMessageListener 类同时添加 MessageListener 接口,实现后在 onMessage 方法中去处理消息。
package cn.itcast.redis.listener;
import org.springframework.data.redis.connection.Message;
public class RedisHessageListener implements MessageListener {
//因为需要运用到数据库,注入数据库相关,在此使用 mybits,hmerinate 和 jdbc 都行
@Autowired
private CouponMapper couponMappe
r;
//处理消息
/**
*完整的处理逻辑如下:
*此时获取的为失效 key 通知
*发送的消息为:key(coupon: 优惠券 id)
* 因此需要的步骤有:
*1.接收到消息获取消息(同时因为获取消息有许多,还需要验证是否是优惠券失效的key)
*2.验证通过后,再从消息中分离出优惠券id
*3.查询数据库获取优惠券对象
*4.设置失效状态,更新数据库
*
*/
public void onMessage(Message message,byte[] pattern){
//通过传入的 message 的 getBody() 方法得到 key,同时还需要强转为 String 类型,因为 getBody() 函数返回值是一个 byte[]数组
String key = new String (message.getBody());
//判断是否是对优惠券的处理,通过if来判断,判断条件为 coupon,因为所有的优惠券都是用 coupon 进行验证的
if(key.startswith( "coupon")) {
//是 coupon 表示对优惠券的处理,之后分离出优惠券 id,在此使用冒号:来拆分数组得到第二个元素 id
String id = key.split(": ")[1];
//得到 id 之后开始查询数据库来获取优惠券对象,在此调用 couponMapper 中的 selectCouponById 方法,同时传入一个 long 类型的参数,而这采用 Long.parseLong(id) 进行了强制转换为 long 类型
Coupon coupon = couponMapper. selectCouponById(Long.parseLong(id));
//设置它的状态,0-有效,1-失效,2-已使用,所以在此设置状态为1已失效
coupon.setState(1);
//同时将 coupon 对象传入,借助 couponMapper 更新
couponMapper.updateCoupon(coupon);
}
}
}
到此全部的处理过程就已经全部结束。
2.将监听类配置到 Spring 配置文件中去
而配置了一个监听类后还需要将其配置到 Spirng 配置文件中去。
首先打开 resources 中的 applicationContext.xml 配置文件,即其主配置文件,其中定义了数据库操作相关内容,同时其中还引入了 applicationContext-data-redis.xml 配置文件,打开后可以看到其中定义了 redisTemplate、connectionFactory 和 poolConfig 等等,以及消息监听,而消息监听中的<constructor-arg></constructor-arg>注入的就是自定义的监听类。
- 代码如下:
<! --配置监听-->
<bean class="org.springframework.data.redis.listener.adapter.NessageListenerAdapter" id="messagelListener">
<constructor-arg>
<bean class="cn.itcast.redis.listener.RedisMessggeListener"/>
</constructor-arg>
</bean>
但在监听容器中的<constructor-arg>的value值不能和之前测试类一样写为随意的 ITCAST,而必须改为__keyevent@0__:expired。
- 代码如下:
<!--监听器容器-->
<bean class="org.springframework.data.redis.Listener.RedisMessageListenerContainer" id="redisContainer">
<!--
*由于需要和 redis 进行交互,注入连接工厂
1.订阅的消息主题
2.接收到消息之后处理的监听器
-->
<property name="connectionFactory" ref="connectionFactory">
</property>
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<! -- topic 的集合:订阅的主题
订阅了一个主题消息:主题的名称(ITCAST)
接收到一条消息之后,交由自定义的消息监听器来进行处理-->
<list>
<bean class="org. springframework.data.redis.listener.ChannelTopic>
<constructor-arg value="__keyevent@0__:expired"></constructor-arg>
</bean>
</list>
</entry>
</map>
</property>
</bean>
</beans>
3.编写测试
完成了监听和配置到 Spring 配置中后,编写程序让 spring 容器去加载消息监听器让其一直不断的监听 redis 服务器通知。测试的代码核心主要为重写一个 main 方法,再在其中使用 ApplicationContext。
- 测试类 RedisTest2 的代码如下:
package cn.itcast.redis;
import org.springframework.context.ApplicationContext;
public class RedisTest2{
public static void main(String[]args) {
ApplicationContext ac = new ClassPathxmlApplicationContext("applicationContext.xml");
}
}
Run AS 等待运行成功后,再次运行 CouponTest 就能够获取新的优惠券,当一分钟的失效时间过后,查看是否将优惠券的状态置为失效。可以看到优惠券上又添加了一条新的数据,状态为0。
在 redis 服务器中输入命令行:keys *也可以查看到 coupon:10这条 id 为10优惠券的新记录出现,输入 ttl coupon:10查看该优惠券的失效时间,等待失效时间过去后关闭服务器,可以看到在控制台显示发送了一条数据,同时伴随这许多的 sql 语句,再次查看数据库后,点击刷新,会发现,状态由0变为1,说明当前借助 redis 消息通知成功的将优惠券的状态变为了失效状态。