SpringBoot4系列09 - 使用消息队列RabbitMQ
上一篇讲缓存,结尾留了个尾巴:缓存解决的是「读得快」,系统里另一半问题「通知得可靠」还空着,这一篇来补。场景还是订单。订单支付成功之后要发短信、要推邮件、要给积分系统记账,这几件事没有一件是下单主链路必须等着的,也没有一件是挂了能装作没看见的。
上一篇讲缓存,结尾留了个尾巴:缓存解决的是「读得快」,系统里另一半问题「通知得可靠」还空着,这一篇来补。场景还是订单。订单支付成功之后要发短信、要推邮件、要给积分系统记账,这几件事没有一件是下单主链路必须等着的,也没有一件是挂了能装作没看见的。
上一篇讲 Redis 收尾的时候留了句尾巴:RedisTemplate 那套是「自己动手」的用法,键怎么起、TTL 给多少、什么时候删,全是我自己说了算。自己动手自由,可这些手工操作散落在业务代码各处,时间一长就没人说得清全貌了。这一篇讲另一条路,Spring 从 3.1 就备好的声明式缓存:方法上贴个注解,命中不进方法体,未命中执行完自动写缓存,删除也是注解一句话的事。
上一篇结尾留了个话头,说从这一篇开始进 P-2,第一个要面对的问题是「Redis 的操作什么时候算成功,跟本地事务没有半点关系」。
这一篇就是。
Redis 不太愿意把自己叫数据库,官方给它的定位是数据结构服务器。String、Hash、List、Set、Sorted Set 这些结构在它这里是一等公民,每个命令都是原子操作,进去了就出结果,没有一半提交一半回滚这回事。
第五篇收尾时留了个话头:一个事务管理器身上,还有哪些东西是配置不出来的。这一篇回答它。
@Transactional 是 Spring 里最像「不用学」的注解:加一行,方法就进事务了。但它有个脾气:用对的时候什么都不用知道,用错了它不告诉你。
最典型的翻车现场:接口返回 422,异常栈打在日志里,调用方按失败处理。然后查库,钱已经扣了。没有报错,没有 WARN,日志上还写着「Initiating transaction commit」,事务管理器认为一切正常,按照默认规则该提交。
第二篇那个订单工程,数据源是启动时自动配好的那一个:yml 里写一句 spring.datasource.url,Boot 就照着它建好 HikariDataSource、SqlSessionFactory 和事务管理器,一行配置类都不用写。
上一篇结尾我留过一个判断:OrderRepository 这个接口再换一次实现,如果还那么顺,分层这件事就算做对了。
这次换 MongoDB。
先把我的结论放这儿:接口契约又是一个字没改,Controller、DTO、状态机、错误响应的形状全部原样,连 /api/orders/{id} 路径都一样。唯一看得见的变化是主键从自增数字变成了 24 位十六进制的 ObjectId。