Spring 声明式事务与传播行为详解:基于高并发业务示例

Spring 声明式事务与传播行为详解

1. 简介

在分布式和高并发系统中,事务管理对于保证数据一致性和系统稳定性至关重要。Spring 提供了声明式事务管理(基于 @Transactional 注解),开发者无需手动管理事务的开启、提交与回滚。通过设置不同的事务传播行为,可以灵活应对业务场景下的方法嵌套、事务独立与局部回滚等需求。

本篇文档将详细介绍:

  • 事务的基本概念及何时存在事务;
  • Spring 中常见的事务传播行为(REQUIRED、REQUIRES_NEW、SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER、NESTED)的作用及应用场景;
  • 一个完整的高并发业务示例,通过代码展示如何在实际项目中使用这些传播行为。

2. 事务基础概念

2.1 什么是事务?

事务是一系列对数据库操作的逻辑单元,这些操作要么全部执行成功,要么全部回滚,保证数据的原子性、一致性、隔离性和持久性(ACID)。在高并发场景下,事务能防止多个并发操作对同一数据造成冲突或不一致,确保业务数据正确。

2.2 事务何时存在?

在 Spring 中,当你调用标注了 @Transactional 注解的方法时:

  • 如果当前线程中不存在事务,Spring 会在方法执行前启动一个新事务;
  • 如果当前线程已经存在事务,根据设置的传播行为,内层方法可能会加入当前事务或启动新的事务。

因此,事务的存在与否由事务边界决定,也依赖于业务逻辑中方法的调用顺序及其传播设置。


3. Spring 声明式事务传播行为

Spring 中常见的事务传播行为有七种,下面详细说明每种行为的特点及其应用场景:

3.1 Propagation.REQUIRED(默认传播行为)

  • 作用说明:
    如果当前存在事务,则加入该事务;否则,新建一个事务。
  • 应用场景:
    核心业务流程,如下订单操作,其中扣减库存、生成订单记录等必须在同一事务中执行,以确保数据一致性。

3.2 Propagation.REQUIRES_NEW

  • 作用说明:
    总是启动一个新的事务。如果当前存在事务,则会挂起当前事务,新事务执行完毕后再恢复之前的事务。
  • 应用场景:
    用于记录审计日志、发送通知或更新统计数据等辅助操作,这些操作需要独立提交,避免因主事务回滚而影响。

3.3 Propagation.SUPPORTS

  • 作用说明:
    如果当前存在事务,则加入事务;如果没有事务,则以非事务方式执行。
  • 应用场景:
    适用于只读查询操作,既可以在事务中运行,也可以在非事务中执行,从而减少不必要的事务开销。

3.4 Propagation.NOT_SUPPORTED

  • 作用说明:
    总是以非事务方式执行操作;如果当前存在事务,则会挂起事务。
  • 应用场景:
    调用外部系统或接口的场景,比如发送短信、邮件等通知操作,不希望事务管理对性能造成影响。

3.5 Propagation.MANDATORY

  • 作用说明:
    当前方法必须在已经存在的事务中执行,否则抛出异常。
  • 应用场景:
    核心数据操作,如财务记录更新等,要求调用方法必须在事务中进行,以确保数据的一致性。

3.6 Propagation.NEVER

  • 作用说明:
    方法不允许在事务中执行;若调用者存在事务,则抛出异常。
  • 应用场景:
    数据采集或统计操作,不希望事务管理导致额外的锁竞争和性能问题。

3.7 Propagation.NESTED

  • 作用说明:
    如果当前存在事务,则启动一个嵌套事务(利用数据库的保存点机制);如果不存在事务,则行为类似于 REQUIRED。
  • 应用场景:
    在复杂业务流程中,某个子步骤出现异常时只回滚该子步骤,而不影响整个事务的提交,如在订单优惠促销中对局部操作进行保护。

4. 高并发场景下的项目示例

下面的示例项目以订单处理为主线,模拟了高并发环境下的业务操作。项目中:

  • OrderService 使用 REQUIRED 传播行为创建订单;
  • AuditService 使用 REQUIRES_NEW 记录审计日志;
  • 同时引入了其他业务场景,如订单查询(SUPPORTS)、外部通知(NOT_SUPPORTED)、财务处理(MANDATORY)、数据分析(NEVER)及订单促销(NESTED)。

4.1 项目结构概览

com.example.demo├── HighConcurrencyDemoApplication.java├── entity│     ├── Order.java│     ├── AuditLog.java│     ├── FinancialRecord.java├── repository│     ├── OrderRepository.java│     ├── AuditLogRepository.java│     └── FinancialRecordRepository.java├── service│     ├── OrderService.java          // REQUIRED 示例(订单创建)│     ├── AuditService.java          // REQUIRES_NEW 示例(审计日志)│     ├── OrderQueryService.java     // SUPPORTS 示例(订单查询)│     ├── ExternalNotificationService.java // NOT_SUPPORTED 示例(外部通知)│     ├── FinancialService.java      // MANDATORY 示例(财务处理)│     ├── AnalyticsService.java      // NEVER 示例(数据分析)│     ├── PromotionService.java      // NESTED 示例(优惠促销)│     └── OrderPromotionService.java // 外层业务调用 PromotionService└── controller├── OrderController.java       // 高并发订单创建示例└── PropagationTestController.java  // 各传播行为测试接口

5. 代码详细展示

下面给出各模块的代码示例。

5.1 应用入口

HighConcurrencyDemoApplication.java

package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class HighConcurrencyDemoApplication {public static void main(String[] args) {SpringApplication.run(HighConcurrencyDemoApplication.class, args);}
}

5.2 实体定义

Order.java

package com.example.demo.entity;import javax.persistence.*;@Entity
@Table(name = "orders")
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String product;private int quantity;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getProduct() { return product; }public void setProduct(String product) { this.product = product; }public int getQuantity() { return quantity; }public void setQuantity(int quantity) { this.quantity = quantity; }
}

AuditLog.java

package com.example.demo.entity;import javax.persistence.*;@Entity
@Table(name = "audit_logs")
public class AuditLog {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private Long orderId;private String message;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public Long getOrderId() { return orderId; }public void setOrderId(Long orderId) { this.orderId = orderId; }public String getMessage() { return message; }public void setMessage(String message) { this.message = message; }
}

FinancialRecord.java
(用于 MANDATORY 示例)

package com.example.demo.entity;import javax.persistence.*;@Entity
@Table(name = "financial_records")
public class FinancialRecord {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String description;private double amount;// getters and setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public double getAmount() { return amount; }public void setAmount(double amount) { this.amount = amount; }
}

5.3 Repository 接口

OrderRepository.java

package com.example.demo.repository;import com.example.demo.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;public interface OrderRepository extends JpaRepository<Order, Long> {
}

AuditLogRepository.java

package com.example.demo.repository;import com.example.demo.entity.AuditLog;
import org.springframework.data.jpa.repository.JpaRepository;public interface AuditLogRepository extends JpaRepository<AuditLog, Long> {
}

FinancialRecordRepository.java

package com.example.demo.repository;import com.example.demo.entity.FinancialRecord;
import org.springframework.data.jpa.repository.JpaRepository;public interface FinancialRecordRepository extends JpaRepository<FinancialRecord, Long> {
}

5.4 各业务服务实现

5.4.1 REQUIRED 与 REQUIRES_NEW 示例

OrderService.java(REQUIRED)
创建订单时开启事务,如果外层不存在事务则新建事务,随后调用审计日志方法。

package com.example.demo.service;import com.example.demo.entity.Order;
import com.example.demo.service.AuditService;
import com.example.demo.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate AuditService auditService;/*** 创建订单,事务传播行为为 REQUIRED。*/@Transactional(propagation = Propagation.REQUIRED)public void createOrder(String product, int quantity) {Order order = new Order();order.setProduct(product);order.setQuantity(quantity);orderRepository.save(order);// 调用审计日志方法,使用 REQUIRES_NEW 启动独立事务记录日志auditService.recordOrderCreation(order);// 模拟业务处理耗时try {Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

AuditService.java(REQUIRES_NEW)
记录订单创建日志,保证即使主事务回滚,日志依然提交成功。

package com.example.demo.service;import com.example.demo.entity.AuditLog;
import com.example.demo.entity.Order;
import com.example.demo.repository.AuditLogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class AuditService {@Autowiredprivate AuditLogRepository auditLogRepository;/*** 记录订单创建日志,使用 REQUIRES_NEW 启动独立事务。*/@Transactional(propagation = Propagation.REQUIRES_NEW)public void recordOrderCreation(Order order) {AuditLog log = new AuditLog();log.setOrderId(order.getId());log.setMessage("Order created for product: " + order.getProduct());auditLogRepository.save(log);}
}
5.4.2 SUPPORTS 示例

OrderQueryService.java
查询订单时使用 SUPPORTS 传播行为,既可以在事务中也可在非事务中执行,适用于只读操作。

package com.example.demo.service;import com.example.demo.entity.Order;
import com.example.demo.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class OrderQueryService {@Autowiredprivate OrderRepository orderRepository;/*** 使用 SUPPORTS 传播行为查询订单,支持事务也可非事务执行。*/@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)public Order getOrderById(Long id) {return orderRepository.findById(id).orElse(null);}
}
5.4.3 NOT_SUPPORTED 示例

ExternalNotificationService.java
外部通知服务使用 NOT_SUPPORTED,确保方法在非事务环境下执行,适用于调用外部接口(如发送短信、邮件)。

package com.example.demo.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class ExternalNotificationService {/*** 使用 NOT_SUPPORTED 传播行为调用外部接口,此方法总在非事务环境下执行。*/@Transactional(propagation = Propagation.NOT_SUPPORTED)public void sendNotification(String message) {// 模拟调用外部接口,例如发送短信或邮件通知System.out.println("Sending external notification: " + message);}
}
5.4.4 MANDATORY 示例

FinancialService.java
要求必须在已有事务中调用,否则抛出异常,适用于财务记录更新等核心操作。

package com.example.demo.service;import com.example.demo.entity.FinancialRecord;
import com.example.demo.repository.FinancialRecordRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class FinancialService {@Autowiredprivate FinancialRecordRepository financialRecordRepository;/*** 更新财务记录,传播行为为 MANDATORY,必须在事务中调用。*/@Transactional(propagation = Propagation.MANDATORY)public void updateFinancialRecord(String description, double amount) {FinancialRecord record = new FinancialRecord();record.setDescription(description);record.setAmount(amount);financialRecordRepository.save(record);}
}
5.4.5 NEVER 示例

AnalyticsService.java
数据分析服务使用 NEVER,确保方法在非事务环境下执行。

package com.example.demo.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class AnalyticsService {/*** 分析数据,传播行为为 NEVER,确保不在事务中执行。*/@Transactional(propagation = Propagation.NEVER)public void processAnalytics(String data) {// 模拟处理数据分析,不依赖事务环境System.out.println("Processing analytics data: " + data);}
}
5.4.6 NESTED 示例

PromotionService.java(NESTED)
在已有事务中启动嵌套事务,允许局部回滚;示例中模拟对偶数订单号抛出异常。

package com.example.demo.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class PromotionService {/*** 应用促销优惠,使用 NESTED 传播行为,在外层事务中建立保存点。* 模拟对偶数订单抛出异常,测试局部回滚。*/@Transactional(propagation = Propagation.NESTED)public void applyPromotion(Long orderId) {System.out.println("Applying promotion for order: " + orderId);// 模拟异常情况:偶数订单号失败if(orderId % 2 == 0) {throw new RuntimeException("Promotion failed for order: " + orderId);}}
}

OrderPromotionService.java
外层方法使用 REQUIRED 事务调用嵌套事务,捕获局部异常后继续提交外层事务。

package com.example.demo.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class OrderPromotionService {@Autowiredprivate PromotionService promotionService;/*** 外层事务处理订单逻辑,并调用嵌套事务应用促销。*/@Transactional(propagation = Propagation.REQUIRED)public void processOrderWithPromotion(Long orderId) {System.out.println("Start processing order: " + orderId);try {promotionService.applyPromotion(orderId);} catch (Exception e) {// 只回滚嵌套事务,不影响外层事务System.out.println("Promotion error handled: " + e.getMessage());}System.out.println("Complete processing order: " + orderId);}
}

5.5 Controller 模块(高并发模拟)

5.5.1 订单 Controller(订单下单示例)

OrderController.java
通过线程池模拟高并发订单创建,每个线程调用 OrderService#createOrder,在自己的线程内独立开启事务。

package com.example.demo.controller;import com.example.demo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@RestController
@RequestMapping("/orders")
public class OrderController {@Autowiredprivate OrderService orderService;/*** 模拟高并发订单创建请求(使用 REQUIRED 与 REQUIRES_NEW)。* 示例调用:POST /orders/create?product=Book&quantity=1*/@PostMapping("/create")public ResponseEntity<String> createOrder(@RequestParam String product, @RequestParam int quantity) {int threadCount = 10;ExecutorService executor = Executors.newFixedThreadPool(threadCount);CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.submit(() -> {try {orderService.createOrder(product, quantity);} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error occurred");} finally {executor.shutdown();}return ResponseEntity.ok("Orders created concurrently");}
}
5.5.2 各传播行为测试 Controller

PropagationTestController.java
提供接口分别测试 SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER、NESTED 这几种传播行为,并模拟高并发调用验证效果。

package com.example.demo.controller;import com.example.demo.service.OrderQueryService;
import com.example.demo.service.ExternalNotificationService;
import com.example.demo.service.FinancialService;
import com.example.demo.service.AnalyticsService;
import com.example.demo.service.OrderPromotionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@RestController
@RequestMapping("/propagation")
public class PropagationTestController {@Autowiredprivate OrderQueryService orderQueryService;@Autowiredprivate ExternalNotificationService externalNotificationService;@Autowiredprivate FinancialService financialService;@Autowiredprivate AnalyticsService analyticsService;@Autowiredprivate OrderPromotionService orderPromotionService;/*** SUPPORTS 测试:并发查询订单(可在事务或非事务中执行)*/@GetMapping("/supports")public ResponseEntity<String> testSupports(@RequestParam Long orderId) {int threadCount = 10;ExecutorService executor = Executors.newFixedThreadPool(threadCount);CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.submit(() -> {try {orderQueryService.getOrderById(orderId);} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error in SUPPORTS test");} finally {executor.shutdown();}return ResponseEntity.ok("SUPPORTS propagation test completed");}/*** NOT_SUPPORTED 测试:并发调用外部通知(总在非事务环境下执行)*/@GetMapping("/notSupported")public ResponseEntity<String> testNotSupported(@RequestParam String message) {int threadCount = 10;ExecutorService executor = Executors.newFixedThreadPool(threadCount);CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.submit(() -> {try {externalNotificationService.sendNotification(message);} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error in NOT_SUPPORTED test");} finally {executor.shutdown();}return ResponseEntity.ok("NOT_SUPPORTED propagation test completed");}/*** MANDATORY 测试:在已有事务中调用财务更新(成功示例)*/@GetMapping("/mandatory/with")@Transactionalpublic ResponseEntity<String> testMandatoryWithTransaction(@RequestParam String description,@RequestParam double amount) {try {financialService.updateFinancialRecord(description, amount);} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("MANDATORY with transaction failed: " + e.getMessage());}return ResponseEntity.ok("MANDATORY propagation test with transaction completed");}/*** MANDATORY 测试:在无事务调用时抛出异常(预期失败)*/@GetMapping("/mandatory/without")public ResponseEntity<String> testMandatoryWithoutTransaction(@RequestParam String description,@RequestParam double amount) {try {financialService.updateFinancialRecord(description, amount);} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("MANDATORY test without transaction failed as expected: " + e.getMessage());}return ResponseEntity.ok("MANDATORY test without transaction unexpectedly succeeded");}/*** NEVER 测试:并发调用数据分析(必须在无事务环境下执行)*/@GetMapping("/never")public ResponseEntity<String> testNever(@RequestParam String data) {int threadCount = 10;ExecutorService executor = Executors.newFixedThreadPool(threadCount);CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.submit(() -> {try {analyticsService.processAnalytics(data);} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error in NEVER test");} finally {executor.shutdown();}return ResponseEntity.ok("NEVER propagation test completed");}/*** NESTED 测试:并发处理订单促销(外层 REQUIRED 事务调用嵌套事务)*/@GetMapping("/nested")public ResponseEntity<String> testNested(@RequestParam Long orderId) {int threadCount = 10;ExecutorService executor = Executors.newFixedThreadPool(threadCount);CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {executor.submit(() -> {try {orderPromotionService.processOrderWithPromotion(orderId);} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error in NESTED test");} finally {executor.shutdown();}return ResponseEntity.ok("NESTED propagation test completed");}
}

6. 总结

  • 事务创建与存在
    Spring 在调用标注了 @Transactional 的方法时会自动判断当前线程是否存在事务。如果没有,则新建事务;如果已存在,则根据传播行为决定是否加入现有事务或启动新事务。
  • 传播行为选择
    • REQUIRED:适用于大多数核心业务流程,保证在同一事务内操作。
    • REQUIRES_NEW:用于独立的辅助操作,如记录日志,不受主事务回滚影响。
    • SUPPORTS:主要用于查询操作,既可在事务中也可在非事务中执行。
    • NOT_SUPPORTED:适用于外部调用,确保不使用事务,以防影响性能。
    • MANDATORY:强制要求在已有事务中调用,适合关键数据更新。
    • NEVER:确保方法在无事务环境下执行,防止因事务管理引发锁竞争。
    • NESTED:允许在外层事务中进行局部回滚,适合部分业务操作需要独立处理异常的场景。
  • 高并发环境下的设计
    通过线程池模拟高并发场景,每个并发请求在独立线程中调用事务方法,保证每个线程都有独立的事务环境。合理选择事务传播行为,可以降低锁竞争、提高性能,同时确保数据一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/31928.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零使用docker并安装部署mysql8.3.0容器

在开始使用docker到完成mysql的安装部署&#xff0c;中间有很多的坑等着 安装docker并配置 sudo yum install docker-ce 启动docker并设置开机启动项 sudo systemctl start docker sudo systemctl enable docker查看docker是否启动 sudo systemctl status docker 或者直接…

golang 静态库 Undefined symbol: __mingw_vfprintf

正常用golang编译一个静态库给 其他语言 调用&#xff0c;编译时报错 Error: Undefined symbol: __mingw_vfprintf 很是奇怪&#xff0c;之前用用golang写静态库成功过&#xff0c;编译也没问题&#xff0c;结果却是截然不同。 试了很多次&#xff0c;发现唯一的差别就是在 …

如何下载一些网上只提供了预览的pdf

有些网站上提供了pdf的预览&#xff0c;但是不提供下载入口 这时候用浏览器调出开发人员工具&#xff08;F12&#xff09;,找Fetch/XHR这个选项&#xff0c;里看启动器中有pdf的那个文件&#xff0c;点选 它。 然后就能找到它的网址了&#xff0c;直接把这个网址选中&#xff…

力扣-数组-34 在排序数组中查找元素的第一个和最后一个位置

思路和时间复杂度 思路&#xff1a;先找到中间数&#xff0c;如果没找到就返回{-1&#xff0c;-1}&#xff0c;如果找到了就以当前节点为中点&#xff0c;向两边扩时间复杂度&#xff1a; 代码 class Solution { public:vector<int> searchRange(vector<int…

一二三应用开发平台——能力扩展:多数据源支持

背景 随着项目规模的扩大&#xff0c;单一数据源已无法满足复杂业务需求&#xff0c;多数据源应运而生。 技术选型 MyBatis-Plus 的官网提供了两种多数据源扩展插件&#xff1a;开源生态的 <font style"color:rgb(53, 56, 65);">dynamic-datasource</fon…

NAFNet:Simple Baselines for Image Restoration

Abstract 近年来&#xff0c;图像复原技术取得了长足的进步&#xff0c;但现有的图像复原方法&#xff08;SOTA&#xff09;系统复杂度也在不断增加&#xff0c;不利于对各种方法的分析和比较。在本文中&#xff0c;我们提出了一种简单的基线&#xff0c;它超越了SOTA方法&…

python语言总结(持续更新)

本文主要是总结各函数&#xff0c;简单的函数不会给予示例&#xff0c;如果在平日遇到一些新类型将会添加 基础知识 输入与输出 print([要输出的内容])输出函数 input([提示内容]如果输入提示内容会在交互界面显示&#xff0c;用以提示用户)输入函数 注释 # 单行注释符&…

基于springboot和spring-boot-starter-data-jpa快速操作mysql数据库

1、创建springboot项目 2、pom.xml文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:…

【Spring】基础/体系结构/核心模块

概述&#xff1a; Spring 是另一个主流的 Java Web 开发框架&#xff0c;该框架是一个轻量级的应用框架。 Spring 是分层的 Java SE/EE full-stack 轻量级开源框架&#xff0c;以 IoC&#xff08;Inverse of Control&#xff0c;控制反转&#xff09;和 AOP&#xff08;Aspect…

VMware安装Windows server 2016

1、新建虚拟机&#xff0c;选择自定义模式 2、选择兼容性 4、命名虚拟机 5、固件类型 EFI 虚拟磁盘类型&#xff0c;不同电脑推荐的类型不同&#xff0c;用默认的就行 删除声卡和打印机 检查网络配置 选择本地的Windows server 2016的系统镜像&#xff0c;系统镜像可以去Window…

【MySQL】增删改查进阶

目录 一、数据库约束 约束类型 NULL约束&#xff1a;非空约束 UNIQUE&#xff1a;唯一约束 DEFAULT&#xff1a;默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY&#xff1a;外键约束 二、表的设计 三、新增 四、查询 聚合查询 聚合函数 GROUP BY子句 HA…

使用Process Explorer、Dependency Walker和PE信息查看工具快速排查dll动态库因库与库版本不一致导致的加载失败问题

目录 1、问题说明 2、使用Process Explorer查看目标dll动态库有没有动态加载起来 3、使用Dependency Walker查看xxpadll.dll库的库依赖关系&#xff0c;找到xxpadll.dll加载失败的原因 4、使用PE信息查看工具查看目标dll库的时间戳 5、关于xxsipstack2.dll中调用xxdatanet…

NCCL如何打印XML拓扑文件,操作说明和源码展示

NCCL源码解读的视频在这&#xff1a;NCCL集合通信源码解读、案例、任务调度、拓扑_哔哩哔哩_bilibili 一、环境变量设置 1.1 命令行环境变量设置 为了打印XML拓扑文件&#xff0c;需要设置NCCL的环境变量NCCL_TOPO_DUMP_FILE。这个环境变量指定了XML拓扑文件的输出路径和文件…

时序数据库 TDengine 化工新签约:存储降本一半,查询提速十倍

化工行业在数字化转型过程中面临数据接入复杂、实时性要求高、系统集成难度大等诸多挑战。福州力川数码科技有限公司科技依托深厚的行业积累&#xff0c;精准聚焦行业痛点&#xff0c;并携手 TDengine 提供高效解决方案。通过应用 TDengine&#xff0c;力川科技助力化工企业实现…

Maven的学习以及安装配置 2024/3/1 idea

1. Maven的安装 1.1 首先查看编程工具合适的Maven版本 我使用的是2024/3/1 版本的idea&#xff0c;接下来我会用这个版本的idea进行演示。idea没有汉化的也可以参考我的步骤。 1、打开idea的设置&#xff0c;搜索Maven&#xff0c;进入Maven设置。 我们可以看到&#xff0c;…

kubernetes——part3-5 核心概念 Service

一、 service作用 使用kubernetes集群运行工作负载时&#xff0c;由于Pod经常处于用后即焚状态&#xff0c;Pod经常被重新生成&#xff0c;因此Pod对应的IP地址也会经常变化&#xff0c;导致无法直接访问Pod提供的服务&#xff0c;Kubernetes中使用了Service来解决这一问题&am…

【脚本】Linux一键扩大虚拟内存的大小

Linux增加虚拟内存其实很简单 就那几个命令&#xff0c;free、mkswap、swapon 但是方便起见我写成了脚本 使用方法 进入你的目录&#xff0c; nano ./install_swap.sh 下面的脚本全文复制&#xff0c;粘贴进去之后&#xff0c;按ctrlx后按y保存 然后运行以下命令 sudo bash …

学习 MySQL 需要知道的 28 个小技巧

前言 随着信息技术的不断发展以及互联网行业的高速增长&#xff0c;作为开源数据库的MySQL得到了广泛的应用和发展。目前MySQL已成为关系型数据库领域中非常重要的一员。 无论是运维、开发、测试&#xff0c;还是架构师&#xff0c;数据库技术都是一个 必备加薪神器&#xff…

【Hive】Hive安装

Hive 第一章 Hive的基础知识 第二章 Hive安装 第三章 DDL&#xff08;Data Definition Language&#xff09;数据定义 第四章 DML&#xff08;Data Manipulation Language&#xff09;数据操作 第五章 Hive查询 第六章 Hive的基础知识 第七章 Hive函数 第八章 分区表和分桶表 …

6.聊天室环境安装 - Ubuntu22.04 - elasticsearch(es)的安装和使用

目录 介绍安装安装kibana安装ES客户端使用 介绍 Elasticsearch&#xff0c; 简称 ES&#xff0c;它是个开源分布式搜索引擎&#xff0c;它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自动发现&#xff0c;索引自动分片&#xff0c;索引副本机制&#xff0c;res…