事务消息
并不是实际消息可回退,而是在实际发送消息之前,有一个预消费的动作。
举例:
比如我准备回家,但是我本身没有钥匙,所以我需要确定家里有人,不然的话我人跑到家才发现家里没人,这不是白跑了吗?所以我先打个电话问问家人在不在家,如果在家,我才出发回家。
实际回家,和打电话 是两件事
也就是说预消费和真实的消费,本身还是不一样的。
图解:
代码:
consumer不需要特殊处理,就不写了
producer是需要专为事务消息做改造的:
ProducerServiceImpl:
@Service
public class ProducerServiceImpl implements ProducerService {
private TransactionMQProducer transactionMQProducer = null;
@PostConstruct
public void initTransactionMQProducer() {
transactionMQProducer = new TransactionMQProducer("transactionGroup");
transactionMQProducer.setNamesrvAddr("localhost:9876");
transactionMQProducer.setRetryTimesWhenSendFailed(1);
try {
transactionMQProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
System.out.println("transactionMQProducer成功");
}
/**
* 发送事务消息
*
* @param topic
* @param tags
* @param content
* @return
*/
@Override
public SendResult sendTranscationMsg(String topic, String tags, String content) {
transactionMQProducer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 预处理
// 比如说
// 设置一个业务场景 提交消息,确认订单
// 生成订单有个前提 就是商品id存在
Map<String, String> properties = msg.getProperties();
String commodityId = properties.get("commodityId");
// 如果商品id不合法,说明无法生成订单
// 合法就允许生成
try {
// 实际去校验合法的时候,肯定是要查库或者查缓存的
boolean check = checkCommodityId(commodityId);
return check ? LocalTransactionState.COMMIT_MESSAGE : LocalTransactionState.ROLLBACK_MESSAGE;
} catch (Exception e) {
return LocalTransactionState.UNKNOW;
}
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
// 预处理超时
// 比如说我们认为重试次数为2时,就算失败
if (2 == msg.getReconsumeTimes()) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
// 认为queueId为100则成功
if (100 == msg.getQueueId()) {
return LocalTransactionState.COMMIT_MESSAGE;
}
return LocalTransactionState.ROLLBACK_MESSAGE;
}
});
return null;
}
/**
* 检验商品id是否合法
*
* @param commodityId
* @return
*/
private boolean checkCommodityId(String commodityId) {
return true;
}
@PreDestroy
public void shutDownProducer() {
if (transactionMQProducer != null) {
transactionMQProducer.shutdown();
}
}
模拟的是:
商品服务调用订单服务,订单服务去校验商品id是否合法,如果不合法,不消费。