当前位置: 首页 > news >正文

本地事务 + 消息队列事务方案设计

Spring Boot 和 RocketMQ

在Spring Boot项目中实现“本地事务 + 消息队列事务”的方案,可以按照以下步骤实现:

  1. 先执行MySQL本地事务操作(未提交)
  2. 随后发送消息到消息队列(如RocketMQ事务消息)
  3. 等待消息队列确认消息投递成功
  4. 提交MySQL事务

以下是基于Spring Boot和RocketMQ的完整代码示例:
确保pom.xml中包含RocketMQ的依赖

<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.3.0</version>
</dependency>

业务场景:订单创建和库存更新
需求:创建订单时,使用本地事务处理订单操作,并发送事务消息给库存服务,通知更新库存。

1. 订单服务:OrderService

@Slf4j
@Service
public class OrderService {@Autowiredprivate RocketMQTemplate rocketMQTemplate;@Autowiredprivate OrderRepository orderRepository;/*** 创建订单并发送事务消息*/@Transactionalpublic void createOrderAndSendMessage(String orderId, String productId, int quantity) {// Step 1: 先执行本地事务(保存订单)log.info("开始创建订单...");Order order = new Order();order.setOrderId(orderId);order.setProductId(productId);order.setQuantity(quantity);order.setStatus("PENDING");orderRepository.save(order);// Step 2: 构造事务消息Message<OrderMessage> message = MessageBuilder.withPayload(new OrderMessage(orderId, productId, quantity)).build();// Step 3: 发送事务消息rocketMQTemplate.sendMessageInTransaction("order-topic",  // 消息主题message,null            // 额外参数);}
}

2. 事务监听器:OrderTransactionListener
事务监听器中,包含本地事务执行逻辑和事务状态回查逻辑。

@Slf4j
@Component
public class OrderTransactionListener implements TransactionListener {@Autowiredprivate OrderRepository orderRepository;/*** 执行本地事务逻辑*/@Overridepublic LocalTransactionState executeLocalTransaction(Message msg, Object arg) {OrderMessage orderMessage = (OrderMessage) SerializationUtils.deserialize(msg.getBody());try {log.info("执行本地事务 - 更新订单状态: {}", orderMessage.getOrderId());// 本地事务:更新订单状态为“CONFIRMED”orderRepository.updateStatus(orderMessage.getOrderId(), "CONFIRMED");return LocalTransactionState.COMMIT_MESSAGE;} catch (Exception e) {log.error("本地事务执行失败: {}", e.getMessage());return LocalTransactionState.ROLLBACK_MESSAGE;}}/*** 回查本地事务状态*/@Overridepublic LocalTransactionState checkLocalTransaction(Message msg) {OrderMessage orderMessage = (OrderMessage) SerializationUtils.deserialize(msg.getBody());String orderId = orderMessage.getOrderId();log.info("回查本地事务状态 - 订单ID: {}", orderId);String status = orderRepository.findStatusByOrderId(orderId);if ("CONFIRMED".equals(status)) {return LocalTransactionState.COMMIT_MESSAGE;} else {return LocalTransactionState.ROLLBACK_MESSAGE;}}
}

3. RocketMQ配置
将事务监听器和生产者绑定。

@Configuration
public class RocketMQConfig {@Beanpublic TransactionMQProducer transactionMQProducer(OrderTransactionListener listener) {TransactionMQProducer producer = new TransactionMQProducer("transaction_producer_group");producer.setNamesrvAddr("127.0.0.1:9876");producer.setTransactionListener(listener);return producer;}
}

4. 消息对象:OrderMessage
用于传递订单信息的消息对象。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderMessage implements Serializable {private String orderId;private String productId;private int quantity;
}

5. 数据库操作:OrderRepository

@Repository
public interface OrderRepository extends JpaRepository<Order, String> {@Modifying@Transactional@Query("UPDATE Order o SET o.status = :status WHERE o.orderId = :orderId")void updateStatus(@Param("orderId") String orderId, @Param("status") String status);@Query("SELECT o.status FROM Order o WHERE o.orderId = :orderId")String findStatusByOrderId(@Param("orderId") String orderId);
}

运行流程

  1. 客户端调用createOrderAndSendMessage方法:
    • 先在MySQL数据库中插入订单数据。
    • 发送“半消息”到RocketMQ。
  2. RocketMQ事务监听器executeLocalTransaction执行:
    • 更新订单状态,表示本地事务已完成。
  3. RocketMQ提交或回滚事务消息:
    • 若本地事务成功,则消息被消费者消费。
    • 若本地事务失败,消息被回滚,不可消费。
  4. RocketMQ自动触发回查逻辑(若消息超时未确认):
    • 查询订单状态,判断事务状态。

优点

  • 保证强一致性:通过事务消息,确保MySQL和消息队列状态一致。
  • 容灾能力:通过回查机制避免网络异常或服务故障导致消息丢失。
  • 解耦性:消息队列将订单服务和库存服务解耦。

注意事项

  • 幂等性处理:消费者侧必须支持幂等逻辑,避免重复消费。
  • 回查性能优化:本地事务状态应快速可查,如可使用缓存或事务日志表。
  • 事务超时:根据业务需求设置合理的事务超时参数,避免长时间占用资源。

Spring Boot 和 RabbitMQ

使用 RabbitMQ 也可以实现“本地事务 + 消息队列事务”的一致性方案,但 RabbitMQ 本身不支持事务消息(不像 RocketMQ)。因此,可以通过以下方式实现类似的机制:

核心思路

  1. 先执行 MySQL 的本地事务(未提交)。
  2. 发送消息到 RabbitMQ,但消息暂存(不被消费者消费)。
  3. 本地事务提交后,确认 RabbitMQ 消息投递(通过 RabbitMQ 的 ConfirmCallback 和手动 ACK)。
  4. 如果 MySQL 事务失败,则丢弃消息或不确认消息投递。

依赖配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

使用 RabbitMQ 的 Confirm 模式,确保消息投递到交换机和队列的可靠性

@Configuration
public class RabbitMQConfig {@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);// 开启消息投递到交换机的确认回调rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {if (ack) {// 消息成功到达交换机log.info("消息成功投递到交换机: {}", correlationData);} else {// 消息投递到交换机失败log.error("消息投递到交换机失败: {}, 原因: {}", correlationData, cause);}});// 开启消息投递到队列的回退回调rabbitTemplate.setReturnsCallback(returned -> {log.error("消息未成功投递到队列: {}", returned.getMessage());});return rabbitTemplate;}@Beanpublic Queue orderQueue() {return new Queue("order-queue", true);}@Beanpublic DirectExchange orderExchange() {return new DirectExchange("order-exchange", true, false);}@Beanpublic Binding binding() {return BindingBuilder.bind(orderQueue()).to(orderExchange()).with("order.routing.key");}
}

1. 订单服务:OrderService

@Service
public class OrderService {@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate OrderRepository orderRepository;@Transactionalpublic void createOrderAndSendMessage(String orderId, String productId, int quantity) {// Step 1: 本地事务 - 保存订单到数据库log.info("开始创建订单...");Order order = new Order();order.setOrderId(orderId);order.setProductId(productId);order.setQuantity(quantity);order.setStatus("PENDING");orderRepository.save(order);// Step 2: 发送 RabbitMQ 消息String messageContent = String.format("订单ID: %s, 产品ID: %s, 数量: %d", orderId, productId, quantity);Message message = MessageBuilder.withBody(messageContent.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN).setCorrelationId(orderId).build();try {rabbitTemplate.convertAndSend("order-exchange", "order.routing.key", message);log.info("事务消息发送成功: {}", messageContent);} catch (Exception e) {log.error("消息发送失败: {}", e.getMessage());throw new RuntimeException("消息发送失败,事务回滚");}}
}

消费者:OrderConsumer

@Slf4j
@Component
public class OrderConsumer {@Autowiredprivate StockService stockService;@RabbitListener(queues = "order-queue")public void handleMessage(String message) {log.info("收到订单消息: {}", message);// Step 1: 解析消息内容String[] parts = message.split(",");String orderId = parts[0].split(":")[1].trim();String productId = parts[1].split(":")[1].trim();int quantity = Integer.parseInt(parts[2].split(":")[1].trim());// Step 2: 执行库存更新逻辑stockService.updateStock(productId, quantity);log.info("库存更新成功,订单ID: {}", orderId);}
}

库存服务:StockService

@Service
public class StockService {@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;public void updateStock(String productId, int quantity) {String redisStockKey = "product_stock_" + productId;Integer stock = redisTemplate.opsForValue().get(redisStockKey);if (stock == null || stock < quantity) {throw new RuntimeException("库存不足");}redisTemplate.opsForValue().set(redisStockKey, stock - quantity);log.info("库存更新成功,产品ID: {}, 剩余库存: {}", productId, stock - quantity);}
}

数据库模型

@Entity
@Data
public class Order {@Idprivate String orderId;private String productId;private int quantity;private String status; // PENDING, CONFIRMED
}

关键点解析

  1. 事务控制
    • Spring 的 @Transactional 确保本地数据库操作是事务性的。
    • 如果 RabbitMQ 消息发送失败,直接抛出异常回滚数据库事务。
  2. 消息可靠性
    • 开启 RabbitMQ 的 Confirm 模式,确保消息成功到达交换机和队列。
    • 消息发送失败时,本地事务回滚,确保 MySQL 和 RabbitMQ 的数据一致性。
  3. 消费者幂等性
    • 需要确保消息消费的幂等性(如使用 Redis 或数据库记录已消费消息的ID)。

虽然 RabbitMQ 不原生支持事务消息,但通过这种“本地事务 + 消息确认机制”的组合,仍可以保证 MySQL 和 RabbitMQ 的一致性。相比 RocketMQ 的事务消息,RabbitMQ 的实现稍复杂,但性能更高,适合对消息投递延迟要求较高的场景。

Spring Boot 和 Kafka

使用 Kafka 同样可以实现“本地事务 + 消息队列事务”的一致性方案,得益于 Kafka 的 事务功能(Kafka Transactions)。Kafka 的事务支持允许将生产消息和消费消息的处理绑定在一个事务中,这样可以保证消息的原子性和一致性。

核心思路

  1. 使用 Kafka 的事务性生产者(TransactionalProducer),确保消息生产的事务性。
  2. 在本地事务中完成 MySQL 数据库操作,同时向 Kafka 提交消息。
  3. 如果事务失败,回滚本地事务,同时 Kafka 消息不会被提交。

Maven 依赖

<dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Kafka 配置

@Configuration
@EnableTransactionManagement
public class KafkaConfig {@Beanpublic ProducerFactory<String, String> producerFactory() {Map<String, Object> props = new HashMap<>();props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // 开启幂等性props.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "order-transactional-id"); // 配置事务IDreturn new DefaultKafkaProducerFactory<>(props);}@Beanpublic KafkaTransactionManager<String, String> kafkaTransactionManager(ProducerFactory<String, String> producerFactory) {return new KafkaTransactionManager<>(producerFactory);}@Beanpublic KafkaTemplate<String, String> kafkaTemplate(ProducerFactory<String, String> producerFactory) {return new KafkaTemplate<>(producerFactory);}
}

订单服务实现

@Service
public class OrderService {@Autowiredprivate KafkaTemplate<String, String> kafkaTemplate;@Autowiredprivate OrderRepository orderRepository;@Transactionalpublic void createOrderAndSendMessage(String orderId, String productId, int quantity) {// Step 1: 本地事务 - 保存订单到数据库log.info("开始创建订单...");Order order = new Order();order.setOrderId(orderId);order.setProductId(productId);order.setQuantity(quantity);order.setStatus("PENDING");orderRepository.save(order);// Step 2: 向 Kafka 发送事务性消息try {kafkaTemplate.executeInTransaction(operations -> {String message = String.format("订单ID: %s, 产品ID: %s, 数量: %d", orderId, productId, quantity);operations.send("order-topic", orderId, message);log.info("事务消息已发送: {}", message);return true;});} catch (Exception e) {log.error("消息发送失败,事务回滚: {}", e.getMessage());throw new RuntimeException("消息发送失败,事务回滚");}}
}

消费者服务实现
消费者服务需要保证幂等性,避免重复消费消息对业务数据造成影响。以下是一个简单的消费者实现示例。

@Slf4j
@Component
public class OrderConsumer {@Autowiredprivate StockService stockService;@KafkaListener(topics = "order-topic", groupId = "order-consumer-group")public void handleOrderMessage(ConsumerRecord<String, String> record) {log.info("收到订单消息: {}", record.value());// Step 1: 解析消息内容String[] parts = record.value().split(",");String orderId = parts[0].split(":")[1].trim();String productId = parts[1].split(":")[1].trim();int quantity = Integer.parseInt(parts[2].split(":")[1].trim());// Step 2: 执行库存更新逻辑stockService.updateStock(productId, quantity);log.info("库存更新成功,订单ID: {}", orderId);}
}

库存服务实现

@Service
public class StockService {@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;public void updateStock(String productId, int quantity) {String redisStockKey = "product_stock_" + productId;Integer stock = redisTemplate.opsForValue().get(redisStockKey);if (stock == null || stock < quantity) {throw new RuntimeException("库存不足");}redisTemplate.opsForValue().set(redisStockKey, stock - quantity);log.info("库存更新成功,产品ID: {}, 剩余库存: {}", productId, stock - quantity);}
}

数据库模型

@Entity
@Data
public class Order {@Idprivate String orderId;private String productId;private int quantity;private String status; // PENDING, CONFIRMED
}

关键点解析

  1. Kafka 的事务支持
    • Kafka 支持事务性生产者,kafkaTemplate.executeInTransaction 确保消息生产和本地事务绑定在一起,保证了最终一致性。
  2. 幂等性消费
    • 消费者需要设计幂等性逻辑,比如通过 Redis 或数据库记录已消费的消息 ID,避免重复消费导致库存多次扣减。
  3. 性能和可靠性
    • Kafka 的事务性能优于 RabbitMQ,但需要注意事务超时和重复消费的情况。

Kafka 的事务支持可以较为优雅地实现本地事务和消息队列事务的统一,与 RabbitMQ 相比,Kafka 的事务机制更适合处理分布式一致性问题,尤其是在高吞吐量场景中表现更加出色。

相关文章:

本地事务 + 消息队列事务方案设计

Spring Boot 和 RocketMQ 在Spring Boot项目中实现“本地事务 消息队列事务”的方案&#xff0c;可以按照以下步骤实现&#xff1a; 先执行MySQL本地事务操作&#xff08;未提交&#xff09;随后发送消息到消息队列&#xff08;如RocketMQ事务消息&#xff09;等待消息队列确…...

pinctrl子系统学习笔记

一、背景 cpu的gpio引脚可以复用成多个功能&#xff0c;如可以配置成I2C或者普通GPIO模式。配置方式一般是通过写引脚复用的配置寄存器&#xff0c;但是不同芯片厂商配置寄存器格式内容各不相同&#xff0c;设置引脚复用无法做到通用且自由的配置&#xff0c;只能在启动初始化…...

使用vue-element 的计数器inputNumber,传第三个参数

使用vue-element 的计数器inputNumber。 其中的change 事件中&#xff0c;默认自带两个参数&#xff0c;currentValue和oldValue&#xff0c;分别代表改变后的数和改变前的数&#xff0c; 如果想要传第三个参数&#xff0c; change"(currentValue, oldValue) > numCha…...

如何从0构建一个flask项目,直接上实操!!!

项目结构 首先&#xff0c;创建一个项目目录&#xff0c;结构如下&#xff1a; flask_app/ │ ├── app.py # Flask 应用代码 ├── static/ # 存放静态文件&#xff08;如CSS、JS、图片等&#xff09; │ └── style.css # 示例…...

Mongoose连接数据库操作实践

文章目录 介绍特点&#xff1a;Mongoose 使用&#xff1a;创建项目并安装&#xff1a;连接到 MongoDB&#xff1a;定义 Schema&#xff1a;创建模型并操作数据库&#xff1a;创建文档&#xff1a;查询文档&#xff1a;更新文档&#xff1a;删除文档&#xff1a;使用钩子&#x…...

centos 7.9 freeswitch1.10.9环境搭建

亲测版本centos 7.9系统–》 freeswitch1.10.9 一、下载插件 yum install -y git alsa-lib-devel autoconf automake bison broadvoice-devel bzip2 curl-devel libdb4-devel e2fsprogs-devel erlang flite-devel g722_1-devel gcc-c++ gdbm-devel gnutls-devel ilbc2...

Gitlab服务管理和仓库项目权限管理

Gitlab服务管理 gitlab-ctl start # 启动所有 gitlab 组件&#xff1b; gitlab-ctl stop # 停止所有 gitlab 组件&#xff1b; gitlab-ctl restart # 重启所有 gitlab 组件&#xff1b; gitlab-ctl status …...

LLMs之Llama-3:Llama-3.3的简介、安装和使用方法、案例应用之详细攻略

LLMs之Llama-3&#xff1a;Llama-3.3的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之LLaMA&#xff1a;LLaMA的简介、安装和使用方法、案例应用之详细攻略 LLMs之LLaMA-2&#xff1a;LLaMA 2的简介(技术细节)、安装、使用方法(开源-免费用于研究和商业用途…...

OpenCV函数及其应用

1. 梯度处理的Sobel算子函数 功能 Sobel算子是一种用于边缘检测的离散微分算子&#xff0c;它结合了高斯平滑和微分求导&#xff0c;用于计算图像亮度的空间梯度。 参数 src&#xff1a;输入图像。 dst&#xff1a;输出图像。 ddepth&#xff1a;输出图像的深度。 dx&#xff…...

vulnhub靶场【DriftingBlues】之3

前言 靶机&#xff1a;DriftingBlues-3&#xff0c;IP地址192.168.1.60 攻击&#xff1a;kali&#xff0c;IP地址192.168.1.16 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24 信息收集 使用nmap扫描端口 网站探测 访…...

文件上传—阿里云OSS对象存储

目录 一、OSS简介 二、OSS基本使用 1. 注册账号 2. 基本配置 (1) 开通OSS (2) 创建存储空间 (3) 修改权限 (4) 配置完成&#xff0c;上传一张图片&#xff0c;检验是否成功。 (5) 创建AccessKey 三、Java项目集成OSS 1. 导入依赖 2. Result.java代码&#xff1a; …...

mybatis-plus超详细讲解

mybatis-plus &#xff08;简化代码神器&#xff09; 地址&#xff1a;https://mp.baomidou.com/ 目录 mybatis-plus 简介 特性 支持数据库 参与贡献 快速指南 1、创建数据库 mybatis_plus 2、导入相关的依赖 3、创建对应的文件夹 4、编写配置文件 5、编写代码 …...

【Linux】--- 进程的概念

【Linux】--- 进程的概念 一、进程概念二、PCB1.什么是PCB2.什么是task_struct&#xff08;重点&#xff01;&#xff09;3.task_struct包含内容 三、task_struct内容详解1.查看进程&#xff08;1&#xff09;通过系统目录查看&#xff08;2&#xff09;通过ps命令查看&#xf…...

Unity NTPComponent应用, 实现一个无后端高效获取网络时间的组件

无后端高效获取网络时间的组件 废话不多说&#xff0c;直接上源码m_NowSerivceTime 一个基于你发行游戏地区的时间偏移&#xff0c; 比如北京时区就是 8, 巴西就是-3&#xff0c;美国就是-5using Newtonsoft.Json; 如果这里报错&#xff0c; 就说明项目没有 NewtonsoftJson插件…...

go语言使用zlib压缩[]byte

在Go语言中&#xff0c;可以使用compress/flate和compress/zlib包来实现对[]byte数据的Zlib压缩。下面是一个简单的示例&#xff0c;展示如何使用这些包来压缩一个字节切片&#xff1a; go package main import ( "bytes" "compress/zlib" "fmt"…...

Windows 配置 Tomcat环境

Windows配置Tomcat 1. 介绍 Tomcat是一个开源的、轻量级的Java应用服务器&#xff0c;在Java Web开发领域应用广泛。以下是关于它的详细介绍&#xff1a; 一、基本概念与背景 定义&#xff1a;Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;下…...

【python从入门到精通】-- 第六战:列表和元组

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…...

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…...

LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

完整代码见&#xff1a;zaizai77/Cherno-OpenGL: OpenGL 小白学习之路 高级GLSL 内建变量 顶点着色器 gl_PointSoze : float 输出变量&#xff0c;用于控制渲染 GL_POINTS 型图元时&#xff0c;点的大小。可用于粒子系统。将其设置为 gl_Position.z 时&#xff0c;可以使点…...

Scala学习记录

dao --------> 数据访问 mode ------> 模型 service ---->业务逻辑 Main -------> UI:用户直接操作&#xff0c;调用Service 改造UI层&#xff1a;...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...