RabbitMQ应用问题——消息补偿机制以及代码示例
RabbitMQ应用问题——消息补偿机制以及代码示例
RabbitMQ应用问题
- 消息可靠性的保障
- 消息补偿机制

详细说明
这里使用了简单的代码进行演示,订单的消费者没有写,在订单的消费同时,发送一条增加积分消息到积分队列。
详细流程途中都有注明。
为了更加清楚代码这里进行表明功能。

gitee地址
1.创建mq-manager父工程
1.1导入依赖
<packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.0</version><relativePath/> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.7</version></dependency></dependencies>
2.创建mq-common子模块
2.1导入依赖
<dependencies><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>
2.2编写实体类
2.2.1Order
package com.qf.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;
import java.util.Date;
/*{ "bizNo": "20200803173145877","status": 1,"price": 34.12,"goodId": 1002,"userId": 100}*///订单
@TableName("orders")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {@TableId(value = "id", type = IdType.AUTO)private Integer id;@TableField(value = "biz_no")private String bizNo; //业务编号@TableField(value = "status")private Integer status;@TableField(value = "price")private BigDecimal price;@TableField(value = "create_time")private Date createTime;@TableField(value = "pay_time")private Date payTime;@TableField(value = "good_id")private Integer goodId;@TableField(value = "user_id")private Integer userId;//exist = false:该属性不使用@TableField(value = "num", exist = false)private Integer num;
}
2.2.2Integral
package com.qf.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Date;//积分
@TableName("integral")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Integral{@TableId(type = IdType.AUTO)private Integer id;@TableField("user_id")private Integer userId;private Long score;private String msg;@TableField("create_time")private Date createTime;
}
2.2.3Msg
package com.qf.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Date;//消息
@TableName("message")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Msg {@TableId(value = "id")private String id;@TableField(value = "exchange")private String exchange;@TableField(value = "routing_key")private String routingKey;@TableField(value = "content")private String content; // 消息的内容@TableFieldprivate Integer status; // 消息的状态@TableField(value = "try_count")private int tryCount; //尝试次数@TableField(value = "create_time")private Date createTime;
}
2.3编写公共参数
2.3.1IntegralConstant
package com.qf.contant;//设置系统中的参数
public class IntegralConstant {// 积分系统队列public final static String INTEGRAL_QUEUE = "integral_queue";// 积分系统交换机public final static String INTEGRAL_EXCHANGE = "integral_exchange";// 积分系统的 routing-keypublic final static String INTEGRAL_ROUTING_KEY= "integral_routing_key";
}
2.3.2DeadConstant
package com.qf.contant;//死信
public class DeadConstant {//死信交换机public static final String DEAD_LETTER_EXCHANGE = "dead_letter_exchange";//死信路由键public static final String DEAD_LETTER_ROUTING_KEY = "dead_letter_routing_key";//死信队列public static final String DEAD_LETTER_QUEUE = "dead_letter_queue";
}
3.编写mq-order子模块
3.1导入公共模块
<dependencies><dependency><groupId>com.qf</groupId><artifactId>mq-common</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>
3.2编写配置文件
server:port: 8080spring:datasource:username: rootpassword: rooturl: jdbc:mysql://localhost:3306/mq?serverTimezone=Asia/Shanghai&characterEncoding=utf8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcerabbitmq:username: guestpassword: guesthost: 192.168.25.129port: 5672publisher-confirm-type: simplepublisher-returns: truemybatis-plus:mapper-locations: classpath:mapper/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#驼峰形式map-underscore-to-camel-case: true
3.3编写启动类
package com.qf;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.qf.mapper")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class,args);}
}
3.4编写OrderController
package com.qf.controller;import com.qf.entity.Order;
import com.qf.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("order")
public class OrderController {@Autowiredprivate OrderService orderService;@PostMapping("insertOrder")public String insertOrder(@RequestBody Order order){orderService.insertOrder(order);return "success";}}
3.5编写OrderService
package com.qf.service;import com.qf.entity.Order;public interface OrderService {/*** 插入订单* @param order*/void insertOrder(Order order);
}
3.6编写OrderServiceImpl
package com.qf.service.impl;import com.alibaba.fastjson.JSON;
import com.qf.contant.IntegralConstant;
import com.qf.entity.Integral;
import com.qf.entity.Msg;
import com.qf.entity.Order;
import com.qf.mapper.MsgMapper;
import com.qf.mapper.OrderMapper;
import com.qf.service.OrderService;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.Date;
import java.util.UUID;@Service
@Transactional
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate MsgMapper msgMapper;@Resourceprivate RabbitTemplate rabbitTemplate;@Overridepublic void insertOrder(Order order) {//插入订单orderMapper.insert(order);//插入积分,是把积分信息发送到消息队列中Integral integral = new Integral();integral.setUserId(order.getUserId());//积分对应的用户id就是下订单的用户idintegral.setScore(10L);integral.setMsg("购物积分");integral.setCreateTime(new Date());//把积分对象,转换为Json类型,发送到消息队列中String integralJson = JSON.toJSONString(integral);//创建消息对象,如果消息消费成功了,再去删除对应的消息Msg msg = new Msg();//分布式环境下,id必须是唯一的,解决方案:百度的uid-generator,美团开源项目LeafString uuid = UUID.randomUUID().toString();msg.setId(uuid);msg.setExchange(IntegralConstant.INTEGRAL_EXCHANGE);//积分对应的交换机msg.setRoutingKey(IntegralConstant.INTEGRAL_ROUTING_KEY);//积分对象的路由的keymsg.setContent(integralJson);//积分的Json对象msg.setStatus(-1);//状态msg.setTryCount(0);//尝试次数msg.setCreateTime(new Date());//时间//插入消息msgMapper.insert(msg);//发送消息,需要把Msg对象的id(就是uuid)传过来,一旦消息消费成功,还要去Msg对应表中把该消息删除CorrelationData correlationData = new CorrelationData(uuid);System.out.println("uuid:" + uuid);System.out.println("correlationData.getId():" + correlationData.getId());//发送rabbitTemplate.convertAndSend(IntegralConstant.INTEGRAL_EXCHANGE,IntegralConstant.INTEGRAL_ROUTING_KEY,buildMessage(integralJson,uuid),correlationData);}//构建消息private Message buildMessage(String body,String messageId){//获取MessagePropertiesBuilder对象MessagePropertiesBuilder messagePropertiesBuilder = MessagePropertiesBuilder.newInstance();//获取MessageProperties对象MessageProperties messageProperties = messagePropertiesBuilder.build();messageProperties.setMessageId(messageId);messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);//消息持久化Message message = new Message(body.getBytes(),messageProperties);System.out.println("message传递的内容:" + new String(message.getBody()));System.out.println("message传递的uuid:" + message.getMessageProperties().getMessageId());return message;}
}
3.7编写OrderMapper
package com.qf.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qf.entity.Order;
import org.springframework.stereotype.Repository;@Repository
public interface OrderMapper extends BaseMapper<Order> {
}
3.8编写MsgMapper
package com.qf.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qf.entity.Msg;
import org.springframework.stereotype.Repository;@Repository
public interface MsgMapper extends BaseMapper<Msg> {
}
3.9编写配置类
3.9.1DeadConfig
package com.qf.config;import com.qf.constant.DeadConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class DeadConfig {//创建队列@Beanpublic Queue createDeadQueue(){return new Queue(DeadConstant.DEAD_LETTER_QUEUE);}//创建交换机@Beanpublic DirectExchange createDeadExchange(){//交换机默认持久化return new DirectExchange(DeadConstant.DEAD_LETTER_EXCHANGE);}//绑定:交换机中的消息可以发送到不同的队列@Beanpublic Binding bindingDeadQueue(){//需要设置routingKeyreturn BindingBuilder.bind(createDeadQueue()).to(createDeadExchange()).with(DeadConstant.DEAD_LETTER_ROUTING_KEY);//和发送消息时的routingKey一致}
}
3.9.2IntegralConfig
package com.qf.config;import com.qf.constant.DeadConstant;
import com.qf.constant.IntegralConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;//路由模式
@Configuration
public class IntegralConfig {//创建队列@Beanpublic Queue createIntegralQueue(){Map<String, Object> arguments = new HashMap<>();arguments.put("x-dead-letter-exchange", DeadConstant.DEAD_LETTER_EXCHANGE);arguments.put("x-dead-letter-routing-key", DeadConstant.DEAD_LETTER_ROUTING_KEY);return new Queue(IntegralConstant.INTEGRAL_QUEUE,true,false,false,arguments);}//创建交换机@Beanpublic DirectExchange createIntegralExchange(){//交换机默认持久化return new DirectExchange(IntegralConstant.INTEGRAL_EXCHANGE);}//绑定:交换机中的消息可以发送到不同的队列@Beanpublic Binding bindingIntegralQueue(){//需要设置routingKeyreturn BindingBuilder.bind(createIntegralQueue()).to(createIntegralExchange()).with(IntegralConstant.INTEGRAL_ROUTING_KEY);//和发送消息时的routingKey一致}}
3.9.3PublisherConfirmAndReturnConfig
package com.qf.config;import com.qf.entity.Msg;
import com.qf.mapper.MsgMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;@Slf4j
@Configuration
public class PublisherConfirmAndReturnConfig implementsRabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback {@Resourceprivate RabbitTemplate rabbitTemplate;@Autowiredprivate MsgMapper msgMapper;@PostConstructpublic void init(){rabbitTemplate.setConfirmCallback(this);rabbitTemplate.setReturnsCallback(this);}@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String s) {//判断if(ack){log.info("已到达broker");log.info("correlationData id is {}",correlationData.getId());//删除存到数据库中的消息//msgMapper.deleteById(correlationData.getId());//通过id删除//设置删除条件HashMap<String, Object> map = new HashMap<>();map.put("id",correlationData.getId());map.put("status",-1);//多条件删除msgMapper.deleteByMap(map);}else{log.info("没有到达broker,实际上消息已经保存到mysql中,也可以保存到redis中");}}//return机制,该方法比confirm先执行,只要未到达队列的时候才执行@Overridepublic void returnedMessage(ReturnedMessage returnedMessage) {log.info("消息未到达队列");//如果消息到达队列不执行以下代码//消息已经从数据库被删除了//考虑人工干预,获取消息信息进行保存String exchange = returnedMessage.getExchange();String routingKey = returnedMessage.getRoutingKey();Message message = returnedMessage.getMessage();//创建消息对象,如果消息消费成功了,再去删除对应的消息Msg msg = new Msg();msg.setId(message.getMessageProperties().getMessageId());msg.setExchange(exchange);//积分对应的交换机msg.setRoutingKey(routingKey);//积分对象的路由的keymsg.setContent(new String(message.getBody()));//积分的Json对象msg.setStatus(-2);//状态可以设置为和之前不一样msg.setTryCount(0);//尝试次数msg.setCreateTime(new Date());//时间//插入消息msgMapper.insert(msg);//做进一步处理:给管理员发邮件,发短信....}
}
4.创建mq-integral子模块
4.1导入依赖
<dependencies><dependency><groupId>com.qf</groupId><artifactId>mq-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.4</version></dependency>
</dependencies>
4.2编写配置文件
server:port: 8081spring:datasource:username: rootpassword: rooturl: jdbc:mysql://localhost:3306/mq?serverTimezone=Asia/Shanghai&characterEncoding=utf8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcerabbitmq:username: guestpassword: guesthost: 192.168.25.134port: 5672listener:simple:retry:enabled: true #开启消息重试max-attempts: 3 #最大重试次数initial-interval: 2000ms #每次重试的时间间隔multiplier: 2 #每次重试时间乘以当前倍数#重试机制必须是自动ack,才能放到死信队列中acknowledge-mode: automybatis-plus:mapper-locations: classpath:mapper/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#驼峰形式map-underscore-to-camel-case: true
4.3编写启动类
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.qf.mapper")
public class IntegralApplication {public static void main(String[] args) {SpringApplication.run(IntegralApplication.class,args);}
}
4.4编写IntegralImpl
package com.qf.service.impl;import com.alibaba.fastjson.JSON;
import com.qf.constant.IntegralConstant;
import com.qf.entity.Integral;
import com.qf.mapper.IntegralMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;import java.util.Random;
import java.util.concurrent.TimeUnit;@Service
public class IntegralImpl {@Autowiredpublic IntegralMapper integralMapper;@Autowiredprivate StringRedisTemplate stringRedisTemplate;// //第一种方式
// @RabbitListener(
// bindings = @QueueBinding(
// value = @Queue(name = IntegralConstant.INTEGRAL_QUEUE,
// durable = "true"
// ),
// key = {IntegralConstant.INTEGRAL_ROUTING_KEY},
// exchange = @Exchange(name = IntegralConstant.INTEGRAL_EXCHANGE, durable = "true")
// ))
// public void insertIntegral(Message message){
// //积分信息
// String integralJson = new String(message.getBody());
// System.out.println(integralJson);
//
// //类型转换
// Integral integral = JSON.parseObject(integralJson, Integral.class);
// System.out.println(integral);
// //插入数据库
// integralMapper.insert(integral);
// }// //第二种方式
// @RabbitListener(queues = IntegralConstant.INTEGRAL_QUEUE)
// public void insertIntegral(Message message) throws InterruptedException {
// //积分信息
// String integralJson = new String(message.getBody());
// System.out.println(integralJson);
//
// //运行成功
// //类型转换
// Integral integral = JSON.parseObject(integralJson, Integral.class);
// System.out.println(integral);
// //插入数据库
// integralMapper.insert(integral);
//
// //测试消息重复消费
// //直到方法执行完毕,才会ack
// Thread.sleep(500000);
//
// //测试消息重试
// //System.out.println("当前系统时间:"+System.currentTimeMillis());
// //运行失败
// //throw new RuntimeException("消息消费异常...");
// }@RabbitListener(queues = IntegralConstant.INTEGRAL_QUEUE)public void receiveIntegralMessage(Message message){//获取要被消息的消息idString messageId = message.getMessageProperties().getMessageId();//判断,如果redis中没有这个消息id的key,则是第一次消费该消息if(!stringRedisTemplate.hasKey(messageId)){//获取积分信息String integralJson = new String(message.getBody());//类型转换Integral integral = JSON.parseObject(integralJson, Integral.class);//插入到数据库integralMapper.insert(integral);//使用hutool工具类生成随机数int randomInt = RandomUtil.randomInt(10, 100);//往redis中也存一份stringRedisTemplate.opsForValue().setIfAbsent(messageId,String.valueOf(randomInt),600, TimeUnit.SECONDS);}}
4.5编写IntegralMapper
package com.qf.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qf.entity.Integral;
import org.springframework.stereotype.Repository;@Repository
public interface IntegralMapper extends BaseMapper<Integral> {
}
5.创建mq-compensate子工程
5.1导入依赖
<dependencies><dependency><groupId>com.qf</groupId><artifactId>mq-order</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>
4.2编写配置文件
server:port: 8082spring:datasource:username: rootpassword: rooturl: jdbc:mysql://localhost:3306/mq?serverTimezone=Asia/Shanghai&characterEncoding=utf8driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcerabbitmq:username: guestpassword: guesthost: 192.168.25.134port: 5672publisher-confirm-type: simplepublisher-returns: truemybatis-plus:mapper-locations: classpath:mapper/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#驼峰形式map-underscore-to-camel-case: true
4.3编写启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class CompensateApplication {public static void main(String[] args) {SpringApplication.run(CompensateApplication.class,args);}
}
4.4编写MassageCompensateTask
package com.qf.task;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.contant.IntegralConstant;
import com.qf.entity.Msg;
import com.qf.mapper.MsgMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.MessagePropertiesBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;import javax.annotation.Resource;
import java.util.List;/**** 消息补偿:隔一段时间,去数据库查询未消费掉的消息,再次执行*/@Configuration
public class MassageCompensateTask {@Autowiredprivate MsgMapper msgMapper;@Resourceprivate RabbitTemplate rabbitTemplate;@Scheduled(cron = "10 * * * * ?")public void compensateTask(){//设置查询条件QueryWrapper<Msg> queryWrapper = new QueryWrapper<>();queryWrapper.eq("status","-2");queryWrapper.lt("try_count","3");//查询消息List<Msg> msgList = msgMapper.selectList(queryWrapper);//判断if(msgList.size() > 0){for(Msg msg : msgList){System.out.println("数据库中的消息id:" + msg.getId());//发送rabbitTemplate.convertAndSend(msg.getExchange(),msg.getRoutingKey(),buildMessage(msg.getContent(),msg.getId()),new CorrelationData(msg.getId()));//设置尝试次数msg.setTryCount(msg.getTryCount() + 1);//修改数据库中的消息msgMapper.updateById(msg);}}}//构建消息private Message buildMessage(String body, String messageId){//获取MessagePropertiesBuilder对象MessagePropertiesBuilder messagePropertiesBuilder = MessagePropertiesBuilder.newInstance();//获取MessageProperties对象MessageProperties messageProperties = messagePropertiesBuilder.build();messageProperties.setMessageId(messageId);messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);//消息持久化Message message = new Message(body.getBytes(),messageProperties);System.out.println("message传递的内容:" + new String(message.getBody()));System.out.println("message传递的uuid:" + message.getMessageProperties().getMessageId());return message;}
}
相关文章:
RabbitMQ应用问题——消息补偿机制以及代码示例
RabbitMQ应用问题——消息补偿机制以及代码示例 RabbitMQ应用问题 消息可靠性的保障 消息补偿机制 详细说明 这里使用了简单的代码进行演示,订单的消费者没有写,在订单的消费同时,发送一条增加积分消息到积分队列。 详细流程途中都有注明…...
量化特征贡献度函数:feature_importances_函数/LGBMClassifier/XGBClassifier
feature_importances_是scikit-learn机器学习库中许多模型对象的属性,在训练模型之后调用该属性可以输出各个特征在模型中的重要性。 示例代码: from sklearn.ensemble import RandomForestRegressor from sklearn.datasets import make_regression# 生…...
总结JVM重要知识点
一.类加载和创建对象的过程 1.类加载 1.编译 : 将源码文件(.java)编译成JVM可以解释的.class文件 . 语法分析>语义分析>注解处理 , 生成class文件 2.加载 : 装载 : 字节码本来存储在硬盘上 , 需要运行时 , 有类加载系统负责将类的信息加载到内存中(方法区) , 使用的是类…...
奇技淫巧第8期
学无止境。 下面是对去年11月至今年5月的零散知识点总结。 春节期间好好放松了一两个月,来校后又懒散的度过了一两个月,直到论文评审意见下来,才开启冲刺模式狂干了一两个月。总的来说,这半年来摸的时间比较多。好,不废…...
这个 归并排序详解过程 我能吹一辈子!!!
文章目录 归并排序概念归并排序算法思路归并排序递归实现归并排序非递归实现 归并排序概念 1945年,约翰冯诺依曼(John von Neumann)发明了归并排序,这是典型的分治算法的应用。 归并排序(Merge sort)是建立…...
docker版jxTMS使用指南:自动生成代码
本文讲解4.0版jxTMS的自动生成代码功能, 整个系列的文章请查看:docker版jxTMS使用指南:4.0版升级内容 docker版本的使用,请参考:docker版jxTMS使用指南 任何一个管理系统都需要对管理对象进行管理,包括最…...
聚观早报 | 小冰启动GPT克隆人计划;ofo创始人在美创业改做咖啡
今日要闻:小冰启动“GPT克隆人计划”;ofo创始人在美创业改做咖啡;OpenAI正准备新的开源AI模型;青年失业率首破20%创新高;微软收购动视暴雪获批 小冰启动“GPT克隆人计划” 5 月 16 日,小冰公司…...
面试造航母,入职拧螺丝,工资离了个大谱...
有粉丝跟我吐槽说:金三银四去面试软件测试岗,真的是面试造航母,入职拧螺丝,工资还低 这种现象很正常,因为找一个测试员,当然希望他能做的业务越多越好,最好像机器猫一样,啥事儿都能…...
Python+selenium自动化元素定位防踩坑
在自动化UI测试过程中常常会在元素定位阶段就踩坑,碰到困扰已久的问题。 以下是个人整理元素定位报错原因和解决方法。 踩坑一:StaleElementReferenceException selenium.common.exceptions.StaleElementReferenceException: Message: stale element re…...
【计算机组成原理】实验一
文章目录 实验一 数据传送实验1. 实验目的2. 实验仪器3. 原理概述4. 实验内容步骤4.1 手动实验环境的建立4.2 手控传送实验 5. 实验结论及问题讨论 实验一 数据传送实验 1. 实验目的 2. 实验仪器 3. 原理概述 4. 实验内容步骤 4.1 手动实验环境的建立 1)初始待令状态 上电或…...
前端022_广告模块_修改功能
广告模块_修改功能 1、需求分析2、Mock添加查询数据3、Mock修改数据4、Api调用回显数据5、提交修改后的数据6、效果1、需求分析 需求分析 当点击 编辑 按钮后,弹出编辑窗口,并查询出分类相关信息进行渲染。修改后点击 确定 提交修改后的数据。 2、Mock添加查询数据 请求URL…...
makefile 学习(3):C++的编译及库文件的生成与链接
1. 介绍 C语言的相关后缀 .a 文件是一个静态库文件.c,.c ,.cp,.cpp,.cc,.cxx 这几种后缀都可以表示c的源文件.h ,.hpp c语言的头文件.i 是c预处理文件.o 目标文件.s汇编语言的文件.so 动态库或者共享库或者称为运行时库 2. C编译 2.1 预处理 g -E helloworld.cpp # 虽…...
Ceph crush运行图
Crush map介绍 ceph集群中由monitor负责维护的运行图包括: Monitor map:监视器运行图osd map:osd运行图PG map:PG运行图Crush map:crush运行图Mds map:mds运行图 crush map是ceph集群物理拓扑的抽象&…...
【分布族谱】泊松分布和二项分布、正态分布的关系
文章目录 泊松分布和二项分布的关系和正态分布的关系 泊松分布 如果在有限时间 ( 0 , 1 ) (0,1) (0,1)内进行 n n n次伯努利实验,那么每次伯努利实验所占用的时间为 1 n \frac{1}{n} n1,按照自然规律,一件事情肯定是时间越长越容易发生&am…...
关于QTreeWidget的setData函数
当使用 Q T r e e W i d g e t I t e m QTreeWidgetItem QTreeWidgetItem 的 s e t D a t a setData setData 方法时,需要传递三个参数,分别是列索引、角色和数据。 列索引:表示要设置数据的列的索引。 Q T r e e W i d g e t I t e m QTre…...
Microsoft Office 2003的安装
哈喽,大家好。今天一起学习的是office2003的安装,这个老版本的office可是XP操作系统的老搭档了,有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统:Windows XP 不建议win7及以上操作系统使用 系统类型ÿ…...
使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理
使用Spring Boot和Spring Cloud实现多租户架构:支持应用多租户部署和管理 一、概述1 什么是多租户架构?2 多租户架构的优势3 实现多租户架构的技术选择 二、设计思路1 架构选型1.1 Spring Boot1.2 Spring Cloud 2 数据库设计3 应用多租户部署3.1 应用隔离…...
智聚北京!相约全球人力资源数智化峰会
人力资源是推动经济社会发展的第一资源。作为我国经济压舱石的中央企业在对标世界一流企业和管理提升方面的持续创新,各行业领军企业围绕组织变革、管理升级、全球化发展走深走实。人力资源管理正从传统职能管理与管控,向紧贴业务战略实现、组织边界和人…...
工业缺陷检测数据及代码(附代码)
介绍 目前,基于机器视觉的表面缺陷检测设备已广泛取代人工视觉检测,在包括3C、汽车、家电、机械制造、半导体与电子、化工、制药、航空航天、轻工等多个行业领域得到应用。传统的基于机器视觉的表面缺陷检测方法通常采用常规图像处理算法或人工设计的特征加分类器。一般而言…...
CentOS 安装MongoDB 6.0
一、安装依赖 yum install libcurl openssl xz-libs 二、下载安装包 安装包下载地址https://www.mongodb.com/try/download/community这里我选择的是 选择RedHat / CentOS 7.0平台的原因是我的操作系统使用的是CentOS 7.0的,需要下载与操作系统匹配的安装包 三、…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用
Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用 Linux 内核内存管理是构成整个内核性能和系统稳定性的基础,但这一子系统结构复杂,常常有设置失败、性能展示不良、OOM 杀进程等问题。要分析这些问题,需要一套工具化、…...
