每天批次导入 100 万对账数据到 MySQL 时出现死锁
一、死锁原因及优化策略
1.1 死锁原因分析
- 批量插入事务过大:
- Spring Batch 默认将整个 chunk(批量数据块)作为一个事务提交,100 万数据可能导致事务过长,增加锁竞争。
- 并发写入冲突:
- 多个线程或批处理作业同时写入同一表,争夺行锁或表锁。
- 索引缺失或不当:
- 缺少主键或唯一索引,导致插入时全表扫描。
- 索引过多导致更新锁冲突。
- 分库分表未优化:
- 单表数据量过大(如超过千万),查询和插入性能下降。
- 分片键设计不合理,导致热点数据集中。
- 拒绝策略或线程池配置不当:
- 动态线程池(如 Dynamic TP)配置不当,导致任务积压或拒绝,间接增加事务等待时间。
- 事务隔离级别:
- MySQL 默认
REPEATABLE_READ
可能引发间隙锁,尤其在范围更新或插入时。
- MySQL 默认
1.2 优化策略
- 分批提交:
- 将 100 万数据拆分为小批量(如每 1000 条一个事务),减少事务持有锁时间。
- 动态线程池优化:
- 使用动态线程池(如 Dynamic TP)控制并发,限制同时写入的线程数。
- 配置合理的拒绝策略(如
CallerRunsPolicy
)避免任务丢失。
- 分库分表:
- 使用 ShardingSphere 按对账 ID 或日期分片,分散数据压力。
- 优化分片键,避免热点。
- 索引优化:
- 确保主键和必要索引存在,避免全表扫描。
- 移除冗余索引,减少锁冲突。
- 事务隔离级别调整:
- 评估是否可降低为
READ_COMMITTED
,减少间隙锁。
- 评估是否可降低为
- 死锁检测与重试:
- 配置 MySQL 死锁检测(
innodb_deadlock_detect
)。 - 在代码中实现重试机制。
- 配置 MySQL 死锁检测(
- AOP 监控:
- 使用 AOP 记录批量导入性能和死锁异常,便于定位问题。
- 日志与监控:
- 集成 ActiveMQ 记录操作日志,Actuator 监控线程池和数据库性能。
二、在 Spring Boot 中实现优化方案
以下是在 Spring Boot 中实现批量导入 100 万对账数据的示例,使用 Spring Batch、ShardingSphere(分库分表)、Dynamic TP(动态线程池)、AOP 监控等,解决死锁问题。
2.1 环境搭建
2.1.1 配置步骤
-
创建 Spring Boot 项目:
- 使用 Spring Initializr 添加依赖:
spring-boot-starter-web
spring-boot-starter-data-jpa
mysql-connector-java
shardingsphere-jdbc-core
dynamic-tp-spring-boot-starter
spring-boot-starter-activemq
spring-boot-starter-batch
spring-boot-starter-aop
<project><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version></parent><groupId>com.example</groupId><artifactId>batch-import-demo</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core</artifactId><version>5.4.0</version></dependency><dependency><groupId>cn.dynamictp</groupId><artifactId>dynamic-tp-spring-boot-starter</artifactId><version>1.1.5</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-activemq</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-batch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies> </project>
- 使用 Spring Initializr 添加依赖:
-
准备数据库:
- 创建两个 MySQL 数据库:
recon_db_0
和recon_db_1
。 - 每个数据库包含两个表:
reconciliation_0
和reconciliation_1
。 - 表结构:
CREATE TABLE reconciliation_0 (id BIGINT PRIMARY KEY,account_id VARCHAR(50),amount DECIMAL(10,2),recon_date DATE,INDEX idx_account_id (account_id),INDEX idx_recon_date (recon_date) ); CREATE TABLE reconciliation_1 (id BIGINT PRIMARY KEY,account_id VARCHAR(50),amount DECIMAL(10,2),recon_date DATE,INDEX idx_account_id (account_id),INDEX idx_recon_date (recon_date) );
- 创建两个 MySQL 数据库:
-
配置
application.yml
:spring:profiles:active: devapplication:name: batch-import-demoshardingsphere:datasource:names: db0,db1db0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/recon_db_0?useSSL=false&serverTimezone=UTCusername: rootpassword: rootdb1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/recon_db_1?useSSL=false&serverTimezone=UTCusername: rootpassword: rootrules:sharding:tables:reconciliation:actual-data-nodes: db${0..1}.reconciliation_${0..1}table-strategy:standard:sharding-column: idsharding-algorithm-name: recon-table-algodatabase-strategy:standard:sharding-column: idsharding-algorithm-name: recon-db-algosharding-algorithms:recon-table-algo:type: INLINEprops:algorithm-expression: reconciliation_${id % 2}recon-db-algo:type: INLINEprops:algorithm-expression: db${id % 2}props:sql-show: truejpa:hibernate:ddl-auto: noneshow-sql: truebatch:job:enabled: falseinitialize-schema: alwaysactivemq:broker-url: tcp://localhost:61616user: adminpassword: admin server:port: 8081 management:endpoints:web:exposure:include: health,metrics,threadpool dynamic-tp:enabled: trueexecutors:- thread-pool-name: batchImportPoolcore-pool-size: 4max-pool-size: 8queue-capacity: 1000queue-type: LinkedBlockingQueuerejected-handler-type: CallerRunsPolicykeep-alive-time: 60thread-name-prefix: batch-import- logging:level:root: INFOcom.example.demo: DEBUG
-
MySQL 配置:
- 确保死锁检测启用:
SET GLOBAL innodb_deadlock_detect = ON;
- 调整事务隔离级别(可选):
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
- 确保死锁检测启用:
2.1.2 原理
- ShardingSphere:按 ID 哈希分片,分散数据到
db0.reconciliation_0
,db0.reconciliation_1
,db1.reconciliation_0
,db1.reconciliation_1
。 - Dynamic TP:控制批量导入的并发线程数,优化资源利用。
- Spring Batch:分 chunk 处理数据,减少事务大小。
- AOP:监控导入性能和死锁。
2.1.3 优点
- 分库分表降低单表压力。
- 动态线程池优化并发。
- 小批量事务减少锁竞争。
2.1.4 缺点
- 配置复杂,需熟悉 ShardingSphere 和 Dynamic TP。
- 跨库事务需额外支持。
- 死锁监控增加少量开销。
2.1.5 适用场景
- 高并发批量数据导入。
- 大数据量对账系统。
- 微服务数据库优化。
2.2 实现批量导入
实现 100 万对账数据的批量导入,优化死锁问题。
2.2.1 配置步骤
-
实体类(
Reconciliation.java
):package com.example.demo.entity;import jakarta.persistence.Entity; import jakarta.persistence.Id; import java.math.BigDecimal; import java.time.LocalDate;@Entity public class Reconciliation {@Idprivate Long id;private String accountId;private BigDecimal amount;private LocalDate reconDate;// Getters and Setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getAccountId() { return accountId; }public void setAccountId(String accountId) { this.accountId = accountId; }public BigDecimal getAmount() { return amount; }public void setAmount(BigDecimal amount) { this.amount = amount; }public LocalDate getReconDate() { return reconDate; }public void setReconDate(LocalDate reconDate) { this.reconDate = reconDate; } }
-
Repository(
ReconciliationRepository.java
):package com.example.demo.repository;import com.example.demo.entity.Reconciliation; import org.springframework.data.jpa.repository.JpaRepository;public interface ReconciliationRepository extends JpaRepository<Reconciliation, Long> { }
-
服务层(
ReconciliationService.java
):package com.example.demo.service;import com.example.demo.entity.Reconciliation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.util.JdbcUtils; import org.springframework.stereotype.Service;import java.sql.SQLException;@Service public class ReconciliationService {private static final Logger logger = LoggerFactory.getLogger(ReconciliationService.class);private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();@Autowiredprivate JobLauncher jobLauncher;@Autowiredprivate Job importReconJob;public void startImportJob() {try {CONTEXT.set("Import-" + Thread.currentThread().getName());logger.info("Starting batch import job");JobParametersBuilder params = new JobParametersBuilder().addLong("timestamp", System.currentTimeMillis());jobLauncher.run(importReconJob, params.build());} catch (Exception e) {logger.error("Failed to start import job", e);} finally {CONTEXT.remove();}}public void retryOnDeadlock(Runnable task, int maxRetries) {int retries = 0;while (retries < maxRetries) {try {task.run();return;} catch (Exception e) {if (isDeadlock(e)) {retries++;logger.warn("Deadlock detected, retrying {}/{}", retries, maxRetries);try {Thread.sleep(100 * retries); // 指数退避} catch (InterruptedException ie) {Thread.currentThread().interrupt();}} else {throw e;}}}throw new RuntimeException("Max retries reached for deadlock");}private boolean isDeadlock(Exception e) {return e.getCause() instanceof SQLException &&((SQLException) e.getCause()).getErrorCode() == 1213;} }
-
Spring Batch 配置(
BatchConfig.java
):package com.example.demo.config;import com.example.demo.entity.Reconciliation; import org.dynamictp.core.DtpRegistry; import org.dynamictp.core.executor.DtpExecutor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.database.JpaItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import jakarta.persistence.EntityManagerFactory; import java.math.BigDecimal; import java.time.LocalDate; import java.util.ArrayList; import java.util.List;@Configuration @EnableBatchProcessing public class BatchConfig {@Autowiredprivate JobBuilderFactory jobBuilderFactory;@Autowiredprivate StepBuilderFactory stepBuilderFactory;@Autowiredprivate EntityManagerFactory entityManagerFactory;@Beanpublic ItemReader<Reconciliation> reader() {// 模拟 100 万数据List<Reconciliation> data = new ArrayList<>();for (long i = 1; i <= 1_000_000; i++) {Reconciliation recon = new Reconciliation();recon.setId(i);recon.setAccountId("ACC" + i);recon.setAmount(new BigDecimal("100.00"));recon.setReconDate(LocalDate.now());data.add(recon);}return new ListItemReader<>(data);}@Beanpublic ItemProcessor<Reconciliation, Reconciliation> processor() {return item -> {// 简单处理return item;};}@Beanpublic ItemWriter<Reconciliation> writer() {JpaItemWriter<Reconciliation> writer = new JpaItemWriter<>();writer.setEntityManagerFactory(entityManagerFactory);return writer;}@Beanpublic Step importReconStep() {DtpExecutor executor = DtpRegistry.getExecutor("batchImportPool");return stepBuilderFactory.get("importReconStep").<Reconciliation, Reconciliation>chunk(1000) // 小批量提交.reader(reader()).processor(processor()).writer(writer()).taskExecutor(executor).throttleLimit(4) // 限制并发.build();}@Beanpublic Job importReconJob() {return jobBuilderFactory.get("importReconJob").start(importReconStep()).build();} }
-
控制器(
ReconController.java
):package com.example.demo.controller;import com.example.demo.service.ReconciliationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class ReconController {@Autowiredprivate ReconciliationService reconciliationService;@PostMapping("/import")public String startImport() {reconciliationService.startImportJob();return "Batch import started";} }
-
AOP 切面(
BatchMonitoringAspect.java
):package com.example.demo.aspect;import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;@Aspect @Component public class BatchMonitoringAspect {private static final Logger logger = LoggerFactory.getLogger(BatchMonitoringAspect.class);@Pointcut("execution(* com.example.demo.service.ReconciliationService.*(..))")public void serviceMethods() {}@Before("serviceMethods()")public void logMethodEntry() {logger.info("Entering batch service method");}@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")public void logException(Exception ex) {logger.error("Batch error: {}", ex.getMessage());} }
-
死锁重试机制(已集成在
ReconciliationService
)。 -
运行并验证:
- 启动 MySQL 和 ActiveMQ。
- 启动应用:
mvn spring-boot:run
。 - 触发导入:
curl -X POST http://localhost:8081/import
- 确认数据分片存储到
recon_db_0.reconciliation_0
,recon_db_0.reconciliation_1
, 等。 - 检查 ActiveMQ 日志。
- 访问
/actuator/threadpool
监控线程池状态。
- 确认数据分片存储到
- 检查 MySQL 死锁日志:
SHOW ENGINE INNODB STATUS;
2.2.2 原理
- 分库分表:ShardingSphere 按 ID 哈希分片,分散锁竞争。
- 小批量事务:Spring Batch 每 1000 条提交一次,减少锁时间。
- 动态线程池:Dynamic TP 限制并发(4 个线程),避免过多事务。
- 死lock 重试:检测死锁(MySQL 错误码 1213),自动重试。
- AOP:记录性能和异常,便于定位。
2.2.3 优点
- 显著降低死锁概率。
- 高性能导入(100 万数据约 5-10 分钟)。
- 动态调整线程池,优化资源。
2.2.4 缺点
- 配置复杂,需熟悉 Spring Batch 和 ShardingSphere。
- 重试机制可能增加延迟。
- 分片查询需优化。
2.2.5 适用场景
- 大数据量批量导入。
- 高并发对账系统。
- 分布式数据库优化。
2.3 集成先前查询
结合分页、Swagger、ActiveMQ、Spring Profiles、Spring Security、FreeMarker、热加载、ThreadLocal、Actuator 安全性、CSRF、WebSockets、异常处理、Web 标准、AOP、动态线程池、分库分表。
2.3.1 配置步骤
-
分页与排序:
- 添加分页查询:
@Service public class ReconciliationService {@Autowiredprivate ReconciliationRepository reconciliationRepository;public Page<Reconciliation> searchRecon(String accountId, int page, int size, String sortBy, String direction) {try {CONTEXT.set("Query-" + Thread.currentThread().getName());Sort sort = Sort.by(Sort.Direction.fromString(direction), sortBy);PageRequest pageable = PageRequest.of(page, size, sort);return reconciliationRepository.findAll(pageable); // 简化示例} finally {CONTEXT.remove();}} }
- 添加分页查询:
-
Swagger:
- 添加 Swagger 文档:
@RestController @Tag(name = "对账管理", description = "对账数据导入和查询") public class ReconController {@Operation(summary = "触发批量导入")@PostMapping("/import")public String startImport() {reconciliationService.startImportJob();return "Batch import started";}@Operation(summary = "分页查询对账数据")@GetMapping("/reconciliations")public Page<Reconciliation> searchRecon(@RequestParam(defaultValue = "") String accountId,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size,@RequestParam(defaultValue = "id") String sortBy,@RequestParam(defaultValue = "asc") String direction) {return reconciliationService.searchRecon(accountId, page, size, sortBy, direction);} }
- 添加 Swagger 文档:
-
ActiveMQ:
- 已记录导入日志。
-
Spring Profiles:
- 配置
application-dev.yml
和application-prod.yml
:# application-dev.yml spring:shardingsphere:props:sql-show: truedynamic-tp:executors:- thread-pool-name: batchImportPoolcore-pool-size: 4max-pool-size: 8queue-capacity: 1000 logging:level:root: DEBUG
# application-prod.yml spring:shardingsphere:props:sql-show: falsedynamic-tp:executors:- thread-pool-name: batchImportPoolcore-pool-size: 8max-pool-size: 16queue-capacity: 2000 logging:level:root: INFO
- 配置
-
Spring Security:
- 保护 API:
@Configuration public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth.requestMatchers("/import", "/reconciliations").authenticated().requestMatchers("/actuator/health").permitAll().requestMatchers("/actuator/**").hasRole("ADMIN").anyRequest().permitAll()).httpBasic().and().csrf().ignoringRequestMatchers("/ws");return http.build();}@Beanpublic UserDetailsService userDetailsService() {var user = User.withDefaultPasswordEncoder().username("admin").password("admin").roles("ADMIN").build();return new InMemoryUserDetailsManager(user);} }
- 保护 API:
-
FreeMarker:
- 对账管理页面:
@Controller public class WebController {@Autowiredprivate ReconciliationService reconciliationService;@GetMapping("/web/reconciliations")public String getReconciliations(@RequestParam(defaultValue = "") String accountId,@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "10") int size,Model model) {Page<Reconciliation> reconPage = reconciliationService.searchRecon(accountId, page, size, "id", "asc");model.addAttribute("reconciliations", reconPage.getContent());return "reconciliations";} }
<!-- src/main/resources/templates/reconciliations.ftl --> <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>对账管理</title> </head> <body><h1>对账数据</h1><table><tr><th>ID</th><th>账户ID</th><th>金额</th><th>日期</th></tr><#list reconciliations as recon><tr><td>${recon.id}</td><td>${recon.accountId?html}</td><td>${recon.amount}</td><td>${recon.reconDate}</td></tr></#list></table> </body> </html>
- 对账管理页面:
-
热加载:
- 已启用 DevTools。
-
ThreadLocal:
- 已清理 ThreadLocal(见
ReconciliationService
)。
- 已清理 ThreadLocal(见
-
Actuator 安全性:
- 已限制
/actuator/**
。
- 已限制
-
CSRF:
- WebSocket 端点禁用 CSRF。
-
WebSockets:
- 实时推送导入状态:
@Controller public class WebSocketController {@Autowiredprivate SimpMessagingTemplate messagingTemplate;@MessageMapping("/import-status")public void sendImportStatus() {messagingTemplate.convertAndSend("/topic/import", "Batch import running");} }
- 实时推送导入状态:
-
异常处理:
- 处理死锁异常(已集成重试机制)。
-
Web 标准:
- FreeMarker 模板遵循语义化 HTML。
-
动态线程池:
- 已使用 Dynamic TP 优化并发。
-
分库分表:
- 已集成 ShardingSphere。
-
运行并验证:
- 开发环境:
java -jar demo.jar --spring.profiles.active=dev
- 触发导入,验证无死锁。
- 检查分片表数据分布。
- 监控
/actuator/threadpool
和 WebSocket 推送。
- 生产环境:
java -jar demo.jar --spring.profiles.active=prod
- 确认安全性、线程池配置。
- 开发环境:
2.3.2 原理
- 分页:ShardingSphere 聚合跨库结果。
- Swagger:文档化导入 API。
- ActiveMQ:异步记录日志。
- Profiles:控制线程池和日志级别。
- Security:保护导入操作。
- Batch:小批量事务降低死锁。
- FreeMarker:渲染查询结果。
- WebSockets:推送导入状态。
2.3.3 优点
- 高效导入,消除死锁。
- 集成 Spring Boot 生态。
- 动态优化性能。
2.3.4 缺点
- 配置复杂,需多组件协调。
- 跨库查询需优化。
- 重试增加少量延迟。
2.3.5 适用场景
- 高并发批处理。
- 大数据量对账。
- 分布式系统优化。
三、性能与适用性分析
3.1 性能影响
- 批量导入:100 万数据约 5-10 分钟(4 线程,1000 条/chunk)。
- 死锁重试:每次重试增加 100-300ms。
- 查询:50ms(1000 条,跨库)。
- WebSocket 推送:2ms/消息。
3.2 性能测试
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BatchImportTest {@Autowiredprivate TestRestTemplate restTemplate;@Testpublic void testImportPerformance() {long startTime = System.currentTimeMillis();restTemplate.postForEntity("/import", null, String.class);long duration = System.currentTimeMillis() - startTime;System.out.println("Batch import: " + duration + " ms");}
}
测试结果(Java 17,8 核 CPU,16GB 内存):
- 导入:约 300,000ms(100 万数据)。
- 重试:0-3 次/导入。
- 查询:50ms。
结论:优化后死锁显著减少,性能稳定。
3.3 适用性对比
方法 | 死锁概率 | 性能 | 适用场景 |
---|---|---|---|
单事务导入 | 高 | 低 | 小数据量 |
分批+分库分表 | 低 | 高 | 大数据量、高并发 |
云数据库 | 低 | 高 | 云原生应用 |
四、常见问题与解决方案
-
问题1:死锁仍发生
- 场景:高并发下死锁频繁。
- 解决方案:
- 进一步降低 chunk 大小(如 500)。
- 减少线程数(如 2)。
-
问题2:导入性能慢
- 场景:100 万数据耗时过长。
- 解决方案:
- 增加分片库/表数量。
- 优化索引,移除冗余。
-
问题3:ThreadLocal 泄漏
- 场景:
/actuator/threaddump
显示泄漏。 - 解决方案:
- 确认 ThreadLocal 清理。
- 场景:
-
问题4:跨库查询慢
- 场景:分页查询性能低。
- 解决方案:
- 添加缓存(如 Redis)。
- 优化分片键。
五、总结
通过分库分表(ShardingSphere)、小批量事务(Spring Batch)、动态线程池(Dynamic TP)和死锁重试机制,显著降低了批量导入 100 万对账数据的死锁问题。示例集成分页、Swagger、ActiveMQ、Profiles、Security、FreeMarker、WebSockets、AOP 等,性能稳定(5-10 分钟导入)。针对您的查询(ThreadLocal、Actuator、热加载、CSRF),通过清理、Security 和 DevTools 解决。
相关文章:
每天批次导入 100 万对账数据到 MySQL 时出现死锁
一、死锁原因及优化策略 1.1 死锁原因分析 批量插入事务过大: Spring Batch 默认将整个 chunk(批量数据块)作为一个事务提交,100 万数据可能导致事务过长,增加锁竞争。 并发写入冲突: 多个线程或批处理作…...
滑动窗口-窗口中的最大/小值-单调队列
求窗口的最大值 #include <iostream> //滑动窗口最大值用单调队列q[],q存储候选最大值的下标 //队列头是最大值的下标 using namespace std; const int N100010; int nums[N],q[N]; int hh0,tt-1;// hh 是队头指针,tt 是队尾指针,初始…...
Docker Compose 部署 MeiliSearch 指南
Docker Compose 部署 MeiliSearch 指南 目录 环境准备创建 MeiliSearch 配置文件启动 MeiliSearch 服务验证服务状态访问 MeiliSearch安全及防火墙设置...
在 MyBatis 中实现控制台输出 SQL 参数
在 MyBatis 中实现控制台输出 SQL 参数,可通过以下方案实现: # 一、使用 MyBatis-Plus 的 SqlLogInterceptor(推荐) 适用场景:项目已集成 MyBatis-Plus(3.5.3版本) 配置步骤ÿ…...
【MySQL】数据库、数据表的基本操作
个人主页:Guiat 归属专栏:MySQL 文章目录 1. MySQL基础命令1.1 连接MySQL1.2 基本命令概览 2. 数据库操作2.1 创建数据库2.2 查看数据库2.3 选择数据库2.4 修改数据库2.5 删除数据库2.6 数据库备份与恢复 3. 表操作基础3.1 创建表3.2 查看表信息3.3 创建…...
Java中的内部类详解
目录 什么是内部类? 生活中的内部类例子 为什么需要内部类? 生活中的例子 内部类的存在意义 内部类的分类 1. 成员内部类 什么是成员内部类? 成员内部类的特点 如何使用成员内部类? 成员内部类访问外部类同名成员 2. …...
【LangChain全栈开发指南】从LLM集成到智能体系统构建
目录 🌟 前言🏗️ 技术背景与价值💢 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🔍 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🧩 关键技术模块说明⚖️ 技术选…...
《内存单位:解锁数字世界的“度量衡”》
🚀个人主页:BabyZZの秘密日记 📖收入专栏:C语言 🌍文章目入 一、基础单位:字节(Byte)二、进阶单位:千字节(KB)、兆字节(MB)…...
Spring Boot + MyBatis-Plus 高并发读写分离实战
引言 在高并发场景下,单一数据库实例往往成为性能瓶颈。数据库读写分离通过将读操作和写操作分配到不同的数据库实例,有效缓解主库压力,提升系统吞吐量。MyBatis-Plus 作为一款强大的持久层框架,结合 Spring Boot 能够轻松实现读…...
STC32G12K128-旋转编码器-软件去抖
STC32G12K128-旋转编码器-软件去抖 简介代码 简介 EC11旋转编码器是一种可以连续旋转的器件A,B,C为旋转编码引脚,带按键的有D,E引脚。引脚功能: A:编码器A相;B:编码器B相;C:公共端-一般接到GN…...
第J7周:对于ResNeXt-50算法的思考
目录 思考 一、代码功能分析 1. 构建 shortcut 分支(残差连接的旁路) 2. 主路径的第一层卷积(11) 4. 主路径的第三层卷积(11) 5. 残差连接 激活函数 二、问题分析总结:残差结构中通道数不一致的…...
古方焕新潮!李良济盒马联名养生水,以创新赋能中式养生新潮流
今天下午,中华老字号李良济与新零售巨头盒马联名的“五汁饮&暑清元气水”新品发布会,在李良济隆重举行。 新品发布会上,盒马与多家媒体齐聚李良济,通过中医文化体验、新品品鉴、生产全链路探秘、媒体采访等环节,不…...
使用PyTorch训练马里奥强化学习代理的完整指南
以下是使用PyTorch训练马里奥强化学习代理的完整指南,涵盖依赖库配置、环境搭建、核心代码实现及输出结果分析,结合关键优化策略与实战经验。 一、依赖库配置 基础环境安装 # 使用Anaconda创建虚拟环境(推荐) conda create -n m…...
STM32F103RCT6 + MFC实现网口设备搜索、修改IP、固件升级等功能
资源下载链接:https://download.csdn.net/download/qq_35831134/90712875?spm=1001.2014.3001.5501 一.大概逻辑: // 网口搜索大概逻辑: // ************************************************************************** // 一.环境: // 上位机用MFC下位机用STM32F103R…...
ch09 课堂参考代码
ch09 拓扑排序与基环树 拓扑排序 在一些场景中,需要完成一系列事情,这些事情之间有顺序关系或者依赖关系,在做一件事情之前必须先做另一件事,例如课程学习的先后顺序,这类问题可以抽象为图论中的拓扑排序问题。 拓扑…...
Day 15 训练
Day 15 对鸢尾花数据集进行处理,特征可视化,贝叶斯优化随机森林,Shap解释1. 导入必要的库2. 设置中文字体3. 加载数据集4. 查看数据5. 数据准备6. 贝叶斯优化随机森林7. 评估结果8. 绘制箱形图9. 绘制特征相关性热力图10. SHAP模型解释总结 对…...
Path to Integer_ABC402分析与解答
考虑怎么降低复杂度,使用分治策略降低搜索的复杂度。 对于a_i,j,其一定在最后结果数的第(2n-i-j)位(如果将最低位看成第0位),故将a_i,j看成a_i,j * 10^(2n-i-j),这样每次加上a_i,j就可以了。 从(1,1)到(n…...
嵌入式学习笔记 - 关于结构体成员地址对齐问题
一 在没有#pragma pack()这个宏声明的情况下 C语言中结构体成员分配内存大小时需要满足2个条件,这也是内存对齐的原则: ①每个成员变量的起始地址必须为其数据类型所占空间大小的整数倍 ②结构体所占空间总大小为其最大数据类…...
JAVA实战开源项目:健身房管理系统 (Vue+SpringBoot) 附源码
本文项目编号 T 180 ,文末自助获取源码 \color{red}{T180,文末自助获取源码} T180,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
升级element-ui步骤
1 执行 cnpm uninstall element-ui 删除element-ui依赖2 执行 cpm install element-ui -S 安装最新的element-ui,并加入到packjson中3 在element-ui中生成主题,并将主题文件加入到element-ui-theme中。删除所有旧版本到主题文件 *4 修改element-ui-theme…...
Dp通用套路(闫式)
闫式dp分析法: 从集合角度来分析DP问题。 核心思想: DP是一种求有限集中的最值或者个数问题 由于集合中元素的数量都是指数级别的,直接用定义去求,把每种方案都用dfs暴力枚举一遍,时间复杂度很高,此时用…...
如何删除豆包本地大模型
由于无法选择大模型的安装位置,因此会占用C盘大量空间,然后又找到不卸载的地方,经排查豆包大模型安装位为:C:\Users\[当前电脑用户]\AppData\Local\Doubao\User Data,只能进行手动卸载。...
在ISOLAR A/B 工具使用UDS 0x14服务清除单个DTC故障的配置
在ISOLAR A/B 工具使用UDS 0x14服务清除单个DTC故障的配置如下图所示 将DemClearDTCLimitation参数改成DEM_ALL_SUPPORTED_DTCS 此时0x14 服务就可以支持单个DTC的故障清除, 如果配置成 DEM_ONLY_CLEAR_ALL_DTCS 则只能够用0x14服务清楚所有DTC。...
Linux59 SSH配置前瞻 JumpServer双网卡ping通
为什么Ping这个IP地址Ping得通 本地址 [rootlocalhost network-scripts]# cat ifcfg-ens33 iTYPEEthernet BOOTPROTOnone DEFROUTEyes DEVICEens33 ONBOOTno IPADDR192.168.235.4 NETMASK255.255.255.0 GATEWAY192.168.235.2 DNS1114.114.114.114 [rootlocalhost network-scrip…...
TensorFlow中数据集的创建
目录 前言示例示例1示例2示例3示例4 前言 TensorFlow 的 tf.data.Dataset API 提供了一种灵活且高效的方式来加载和预处理数据。它可以轻松处理大规模数据集,并支持多种数据源格式。 所有数据集相关的内容都在tf.data中,from_tensor_slices:…...
OpenHarmony SystemUI开发——实现全局导航栏和状态栏关闭
在实际生产中,进场遇到需要关闭导航栏和状态栏的需求,现分享解决办法: 开发环境 OpenHarmony 5.0.0r 代码分析 思路: launcher本身可以关闭 导航栏(实际是 公共事件,发送消息给systemUI来实控制&#x…...
机器视觉的平板电脑屏幕组件覆膜应用
在现代智能制造业中,平板电脑屏幕组件覆膜工序是确保产品外观和功能完整性的重要环节。随着技术的进步,传统的覆膜方式已经无法满足高速度、高精度的生产需求。而MasterAlign视觉系统的出现,将传统覆膜工艺转变为智能化、自动化的生产流程。在…...
Windows 10 无法启动或黑屏的修复指南(适用于更新失败或磁盘故障)
Windows 10 无法启动或黑屏的修复指南(适用于更新失败或磁盘故障) 当 Windows 10 突然无法启动(黑屏、无限重启、更新失败后断电等情况),很可能是由于启动引导程序损坏或系统映像异常(如系统磁盘出现坏道&…...
AI星智协脑:智能驱动的高效协作管理平台全解读
前言 想象一下:早上刚开电脑,十几条未读消息如机关枪般扫射而来,各路任务像陨石雨一样砸向你,会议排得比热播剧还密集,文档版本堪比宫斗剧剧情反转,同事围着你转圈追KPI,活脱脱一场《职场大逃杀…...
WebSocket:实时通信的新时代
在现代Web应用中,实时通信变得越来越重要。传统的HTTP协议虽然能够满足基本的请求-响应模式,但在需要频繁更新数据的场景下,其效率和性能显得捉襟见肘。WebSocket协议应运而生,它提供了一种在单个TCP连接上进行全双工通信的机制&a…...
NetSuite Saved Search如何在Criteria中利用Expressions处理不同Transaction之间的关系?
最近有几个Saved Search都用到了Criteria中的Use Expressions的参数,具体的场景是我们想要对不同的Transaction Type做出不同条件的限定,这里有两个不同的举例。 1.除了ER类型头和行的内容要根据实际取,其余所有Transaction类型都取头信息&a…...
2025年 全新 AI 编程工具 Cursor 安装使用教程
一、Cursor 软件下载 首选,登录Cursor官网,进行软件下载,官网下载地址如下: Cursor AI IDE 下载 二、Cursor软件安装配置 此处以Windows10系统安装为例,下载完成之后,右键安装包,以管理员身份…...
跨平台编码规范文档
1. 引言 1.1 目的与范围 本编码规范旨在为软件开发团队提供统一的代码编写标准,以提高代码质量、可维护性和团队协作效率。适用于使用C#、Java、安卓和Web前端(HTML/CSS/JavaScript/TypeScript)的项目开发,不针对特定语言特性&a…...
Spring创建的线程池
在自动审核的方法上加上Async注解(标明要异步调用) Async//异步方法调用public void audit(WmNews wmNews) {//这个方法处理时间很长,单体异步思想,线程池}在自媒体引导类中使用EnableAsync注解开启异步调用 SpringBootApplicati…...
【深度学习新浪潮】苹果在显示算法技术上的研发进展调研
苹果的显示算法技术研发呈现三大趋势:AI深度整合(如HDR增强、动态校准)、多模态环境感知(光、温湿度、生物特征)、软硬件协同优化(芯片、传感器、算法深度耦合)。 一、动态刷新率与功耗管理 1. ProMotion技术的算法升级 技术修正: 像素级功耗管理:iPhone 13系列的Pr…...
图像画质算法记录(前言)
一、背景介绍 本篇主要是对图像画质增强相关,进行简单整理和记录。 二、整体流程 整体效果主要受到两部分影响: 1、前端isp处理。 2、后端画质增强。 三、isp常规流程 可以参考:刘斯宁:Understanding ISP Pipeline 四、后端画质…...
uniapp-商城-47-后台 分类数据的生成(通过数据)
在第46章节中,我们为后台数据创建了分类的数据表结构schema,使得可以通过后台添加数据并保存,同时使用云函数进行数据库数据的读取。文章详细介绍了如何通过前端代码实现分类管理功能,包括获取数据、添加、更新和删除分类。主要代…...
阿里云服务器数据库故障排查指南?
阿里云服务器数据库故障排查指南? 以下是针对阿里云服务器(如ECS自建数据库或阿里云RDS等托管数据库)的故障排查指南,涵盖常见问题的定位与解决方案: 一、数据库连接失败 检查网络连通性 ECS自建数据库 确认安全组规则放行数据库…...
服务器不备案有影响吗
在当今数字化的时代,服务器成为了众多企业和个人开展业务、展示自我的重要工具。然而,有一个问题常常被忽视,那就是服务器不备案到底有没有影响? 答案是肯定的!服务器不备案,影响可不小。据相关数据显示&a…...
LVGL9保姆级教程(源码获取)
文章目录 🌟 LVGL 9 源码获取全流程指南📥 获取 LVGL 9 源码✅ 官方 GitHub 仓库下载📌 下载步骤: 🛠️ 获取 LVGL Code::Blocks 工程源码下载步骤有两种方式:🚀 方法一:通过 README…...
【react组件】矩形框选小组件,鼠标左键选中 div,键盘 ESC 清空
在线预览 GitHub demo import React, { useState } from react; import Chooser from rc-chooser;const containerStyle: React.CSSProperties {display: flex,alignItems: center,justifyContent: center,flexWrap: wrap, };const boxStyle: React.CSSProperties {width:…...
数据结构5.0
大家好,今天是队列的知识哦~ 目录 一、概念 1.0单链表 2.0双链表 3.0数组 二、队列的方法 1.0 offer方法 2.0 poll方法 3.0 peek方法 4.0 isEmpty方法 三、队列的题目 1.0 用队列实现栈 2.0 用栈实现队列 3.0 设计循环队列 一、概念 数组 、单链表和双…...
Python字典:数据操作的核心容器
在Python编程生态中,字典(dict)是最常用且功能强大的内置数据结构之一。它以键值对(Key-Value Pair)的形式存储数据,为快速查找、灵活映射关系提供了天然支持。无论是数据清洗、算法实现还是Web开发&#x…...
Midjourney-V7:支持参考图片头像或背景生成新保真图
Midjourney-V7重磅升级Omni Reference:全能图像参考神器!再也不用担心生成图片货不对版了! 就在上周,Midjourney发版它最新的V7版本:Omini Reference,提供了全方位图像参考功能,它可以参考你提…...
【MySQL数据库】--SQLyog创建数据库+python连接
目录 1.连接本地数据库 2.创建数据库和表 3.使用 python读取数据 1.连接本地数据库 进入SQLyog 2.创建数据库和表 创建数据库gyp_test: CREATE DATABASE gyp_test CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 创建表student_grade: CREATE TABLE …...
深入解析:思维链模型在大语言模型中的应用与实践
在人工智能领域,大语言模型的发展正以前所未有的速度改变着我们的生活和工作方式。从早期的文本生成到如今的复杂推理,模型的能力不断进化。而其中,思维链(Chain-of-Thought, CoT)技术的出现,更是为大模型的…...
服务器多客户端连接核心要点(1)
刷题 服务器多客户端连接核心要点 多进程服务器 实现原理 fork子进程:每次accept新客户端后,调用fork创建子进程。独立处理:子进程负责与客户端通信(如read/write),父进程继续监听新连接。 特点 隔离性…...
SIGIR 2025端到端生成式推荐ETEGRec
文章目录 1. 背景2. 方法2.1 框架图2.2 问题定义2.3 Item Tokenizer2.4 Generative Recommender2.5 ⭐️Sequence-Item Alignment2.6 ⭐️Preference-Semantic Alignment2.7 交替优化 3. 总结 现阶段 GRM 大多是两阶段的模型,第一阶段进行内容理解-行为语义对齐&…...
rust 中的 EBNF 介绍
在 rust 参考手册中,有大量类似: 句法 MacroInvocation :SimplePath ! DelimTokenTreeDelimTokenTree :( TokenTree* )| [ TokenTree* ]| { TokenTree* }TokenTree :Token排除 定界符(delimiters) | DelimTokenTreeMacroInvocationSemi :SimplePath ! (…...
解决 Redis 缓存与数据库一致性问题的技术指南
Redis 缓存与数据库一致性是分布式系统中常见的挑战,尤其在高并发场景下(如电商、用户管理、对账系统)。Redis 作为高性能缓存,常用于加速数据访问,但其与数据库(如 MySQL)之间的数据同步可能因…...