参考:https://news.sohu.com/a/566698836_121124376
背景:为了更快的响应客户端的请求,针对大量的记录需要入库(插入数据库),通过MQ实现异步入库。
注意:MQ是异步的,有可能还发生重试, 所以需要做好重复消费的问题。也需要做好插入数据失败后,重写的问题。
/** * @desc : 异步入库 **/ private void asyncInsertToDb(){ // 准备好插入的对象 ActivityPlayerTaskDO playerTaskDO = new ActivityPlayerTaskDO(); // MQ的传输对象,指定哪个接口的哪个方法 执行插入操作(含参数)。 Map<String,Object> map = new HashMap<>(); map.put("BeanName", SpringContextUtil.getBeanName(IActivityPlayerTaskService.class)); map.put("BeanMethod", "savePlayerTask"); Object[] params = new Object[1]; params[0] = playerTaskDO; map.put("params", params); // 写到MQ中 rabbitTemplate.convertAndSend(RabbitMqTaskConfig.PLATFORM_GAME_TASK_DIRECT_EXCHANGE, RabbitMqTaskConfig.PLATFORM_GAME_TASK_ASYNC_WRITE_DB_QUEUE_KEY, map); }
MQ接收到请求后的处理:
/** * @desc : 异步执行sql,写数据库 **/ @Override public Boolean asyncWriteDb(Map<String, Object> mqParam){ Object beanName = mqParam.get("BeanName"); if(beanName == null){ return Boolean.FALSE; } Object beanMethod = mqParam.get("BeanMethod"); if(beanMethod == null){ return Boolean.FALSE; } Object params = mqParam.get("params"); if(params == null || !(params instanceof Object[])){ return Boolean.FALSE; } Object service = SpringContextUtil.getBean((String)beanName); Object[] paramArray = (Object[])params; Class<? extends Object>[] paramClass = new Class[paramArray.length]; for (int i = 0; i < paramArray.length; i++) { if(paramArray[i] instanceof List){ paramClass[i] = List.class; }else { paramClass[i] = paramArray[i].getClass(); } } // 找到方法 Method method = ReflectionUtils.findMethod(service.getClass(), (String)beanMethod,paramClass); // 根据 服务名称 ,方法名 反射调用 Object result = ReflectionUtils.invokeMethod(method, service, paramArray); if(result instanceof Boolean){ //失败后,写延迟队列,一分钟后重试,MQ Boolean bool = (Boolean)result; if(!bool) { log.error("异步写数据库,失败了,写延迟队列(通过延迟队列实现失败后的重写),service.getClass={},beanMethod={}",service.getClass(),beanMethod); rabbitTemplate.convertAndSend(RabbitMqTaskConfig.PLATFORM_GAME_TASK_DELAY_EXCHANGE, RabbitMqTaskConfig.PLATFORM_GAME_TASK_ASYNC_WRITE_DB_DELAY_QUEUE_KEY, mqParam, message -> { message.getMessageProperties().setHeader("x-delay", 60000); return message; }); } return bool; } return Boolean.FALSE; }