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

解决 Spring Boot 多数据源环境下事务管理器冲突问题(非Neo4j请求标记了 @Transactional 尝试启动Neo4j的事务管理器)

0. 写在前面

到底遇到了什么问题?

简洁版:

在 Oracle 与 Neo4j 共存的多数据源项目中,一个仅涉及 Oracle 操作的请求,却因为 Neo4j 连接失败而报错。根本原因是 Spring 的默认事务管理器错误地指向了 Neo4j,导致不相关的请求也受到了 Neo4j 连接状态的影响。

详细版:

在包含 Oracle 和 Neo4j 数据库的多数据源 Spring Boot 项目中,一个业务逻辑上仅需访问 Oracle 数据库的 API 请求(标记了 @Transactional ),在执行时却意外地尝试启动 Neo4j 事务。当 Neo4j 数据库无法连接时,这个本应只与 Oracle 交互的请求,反而因为 Neo4j 的连接或事务错误而失败。

1. 背景

本项目是一个基于 Spring Boot 的应用,集成了多种数据源:

  • 两个 Neo4j 图数据库实例(分别用于开发/生产环境,通过 spring.dev.neo4j.* 和 spring.prod.neo4j.* 配置)。
  • 一个 Oracle 关系型数据库(通过 dynamic-datasource-spring-boot-starter 管理,主数据源名为 dsPrimary )。
  • 使用 Mybatis-Plus 作为 Oracle 数据库的 ORM 框架。
  • 使用 Spring 的 @Transactional 注解进行事务管理。

2. 问题描述

在开发过程中,当两个 Neo4j 数据库实例宕机或无法连接时,调用一个 仅涉及 Oracle 数据库 的 API(例如 /xxx/xx/saveXxx )时,应用程序抛出异常,导致该 API 不可用。

初始错误:

org.springframework.transaction.TransactionSystemException: Could not open a new Neo4j session: Unable to connect to [Neo4j IP]:7687...; nested exception is org.neo4j.driver.exceptions.ServiceUnavailableException: Unable to connect to [Neo4j IP]:7687...at org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager.doBegin(Neo4jTransactionManager.java:313)...

这表明即使 API 不直接操作 Neo4j,Spring 仍然尝试启动一个 Neo4j 事务。

3. 分析过程

  1. 初步诊断 : 错误发生在 Neo4jTransactionManager 的 doBegin 方法中。这通常意味着 Neo4j 的事务管理器被配置为 Spring 的 默认(Primary)事务管理器 。当 Spring 遇到 @Transactional 注解且未指定特定事务管理器时,它会尝试使用默认的事务管理器,即使该方法本身不涉及 Neo4j。检查发现, ProdNeo4jConfig.java 中的 prodTransactionManager Bean 可能被标记了 @Primary 。
  2. 尝试移除 Neo4j 的 @Primary : 移除了 prodTransactionManager Bean 上的 @Primary 注解。
  3. 出现新错误 : 移除后,再次调用该 API,出现 NoUniqueBeanDefinitionException 。
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.TransactionManager' available: expected single matching bean but found 2: devTransactionManager,prodTransactionManager

这表明:

  • 该 API 确实需要事务管理(其对应 Service 方法上有 @Transactional 注解)。
  • Spring 容器中存在多个 PlatformTransactionManager 类型的 Bean(至少有 devTransactionManager 和 prodTransactionManager )。
  • 由于没有 Bean 被标记为 @Primary ,Spring 无法确定默认使用哪一个。
  1. 区分默认数据源与主事务管理器 : 我在 application-dev.yml 中配置了 spring.datasource.dynamic.primary: dsPrimary 。需要明确,此配置仅告知 dynamic-datasource-spring-boot-starter 库哪个数据源是默认的, 并不能 指定哪个 PlatformTransactionManager Bean 是 Spring 事务管理的 @Primary Bean。
  2. 尝试切换数据源配置 : 为了简化问题,尝试将数据源配置从 dynamic-datasource 改回标准的 spring.datasource.druid.* 。
    • 问题 5.1 : 启动报错 CannotFindDataSourceException: dynamic-datasource can not find primary datasource 。原因是 application.yml 中排除了 com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure ,导致 Spring Boot 无法根据 spring.datasource.druid.* 自动创建 DataSource 。
    • 解决 5.1 : 移除对 DruidDataSourceAutoConfigure 的排除。
spring:autoconfigure:exclude: # - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  • 问题 5.2 : 启动后仍然报错 NoUniqueBeanDefinitionException ,且错误信息中 只列出了 Neo4j 的事务管理器 ( devTransactionManager , prodTransactionManager )。这表明即使启用了 Druid 自动配置,Oracle 对应的 DataSourceTransactionManager 也没有被成功创建或注册为 Bean,或者 Spring 因某种原因未能找到它。
  1. 确定最终方向 : 无论是使用标准 Druid 配置还是 dynamic-datasource ,最可靠的方法是 显式地在 Java 配置中定义 Oracle 数据库(即 dsPrimary )对应的事务管理器,并将其标记为 @Primary 。

4. 解决方案

决定继续使用 dynamic-datasource-spring-boot-starter 以保留其灵活性,并通过 Java 配置显式定义主事务管理器。

在 对应工程的对应目录下新增(或者修改对应的)一个配置类 DataSourceConfig.java :

package com.xxx.xxxx.config; // 使用项目实际的包路径import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;@Configuration
public class DataSourceConfig {/*** 显式定义与动态数据源关联的事务管理器。* @param dataSource Spring 容器会自动注入由 dynamic-datasource-spring-boot-starter 创建的代理 DataSource Bean。*                   这个代理 DataSource 知道如何根据上下文切换到 dsPrimary 或其他数据源。* @return 标记为 @Primary 的事务管理器*/@Bean("transactionManager") // 使用标准的 "transactionManager" 作为 Bean 名称@Primary // <--- 关键:标记为主要事务管理器public PlatformTransactionManager transactionManager(DataSource dataSource) {// 使用注入的动态数据源代理来创建事务管理器return new DataSourceTransactionManager(dataSource);}
}

实施效果:

添加此配置类后,Spring 容器中存在三个 PlatformTransactionManager Bean:

  • devTransactionManager (Neo4j)
  • prodTransactionManager (Neo4j)
  • transactionManager (Oracle, 使用动态数据源代理, @Primary )

当调用仅涉及 Oracle 且标记了 @Transactional 的 API 时,Spring 会自动选用被 @Primary 标记的 transactionManager ,不再尝试使用 Neo4j 的事务管理器,也解决了 NoUniqueBeanDefinitionException 。应用程序在 Neo4j 宕机时,涉及 Oracle 的 API 可以正常工作。

5. 关键点总结

  • 在 Spring Boot 中, @Primary 注解用于指定在存在多个同类型 Bean 时应优先注入或使用的 Bean。对于事务管理,它指定了默认的 PlatformTransactionManager 。
  • dynamic-datasource-spring-boot-starter 的 spring.datasource.dynamic.primary 配置项用于指定该库内部的默认数据源,与 Spring 的 @Primary 事务管理器是两个不同的概念。
  • 在包含多个事务管理器(例如,连接不同类型数据库)的环境中,必须明确指定一个事务管理器为 @Primary ,以供未显式指定事务管理器名称的 @Transactional 注解使用。
  • 当使用 dynamic-datasource-spring-boot-starter 时,配置 @Primary 的 DataSourceTransactionManager 需要注入由该库提供的 代理 DataSource Bean 。
  • 注意检查 spring.autoconfigure.exclude 配置,避免意外排除了必要的自动配置类。

6. 涉及文件

application.yml

server:port: 8080servlet:context-path: /xxxspring:profiles:active: devautoconfigure:exclude: - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure- org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfigurationdata:neo4j:database: neo4jprod:neo4j:uri: bolt://ip:port1authentication:username: xxxpassword: xxxxdatabase: xxxdev:neo4j:uri: bolt://ip:port2authentication:username: xxxpassword: xxxxxdatabase: xxxdatasource: dynamic: strict: falseprimary: dsPrimarydruid: validation-query: SELECT 1 FROM DUALinitial-size: 5min-idle: 0max-active: 100max-wait: 10000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒time-between-eviction-runs-millis: 30000# 配置一个连接在池中最小生存的时间,单位是毫秒min-evictable-idle-time-millis: 1800000test-while-idle: truetest-on-borrow: falsetest-on-return: false#线程溢出检测控制remove-abandoned: true#线程溢出时间控制(秒)remove-abandoned-timeout-millis: 120#线程溢出日志log-abandoned: false# 是否缓存preparedStatement,也就是PSCachepool-prepared-statements: falsemax-pool-prepared-statement-per-connection-size: 0# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connection-properties: druid: stat: # 合并参数化的SQLmergeSql: trueslowSqlMillis: 5000# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙,'log4j'是用来输出统计数据的filters: statmybatis-plus:configuration:# 驼峰命名,默认true-开启map-underscore-to-camel-case: falsejdbc-type-for-null: 'null'global-config:db-config:# 字段验证策略,not-null默认策略,不会对null做处理update-strategy: ignoredinsert-strategy: not-nullmapper-locations: classpath*:/mapper/*Mapper.xml,classpath*:/mapper/**/*Mapper.xml

application-dev.yml

spring: neo4j:uri: bolt://ip:portdata:neo4j:database: xxxdatasource: dynamic: datasource: dsPrimary: driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:@ip:port/xxxusername: xxxpassword: xxxxxx
neo4j:authentication:username: xxxpassword: xxxxx

DevNeo4jConfig.java

import org.neo4j.driver.AuthToken;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.transaction.PlatformTransactionManager;import java.net.URI;@Configuration
@ConditionalOnProperty(prefix = "spring.dev.neo4j", name = "uri")
public class DevNeo4jConfig extends AbstractMultiNeo4jConfig {@Bean("devCypherService")public CypherService devCypherService(@Qualifier("devNeo4jClient") Neo4jClient neo4jClient) {return new CypherServiceImpl(neo4jClient);}@Bean("devCypherQueryService")public CypherQueryService devCypherQueryService(@Qualifier("devNeo4jClient") Neo4jClient neo4jClient) {return new CypherQueryServiceImpl(neo4jClient);}@Bean("devNeo4jClient")public Neo4jClient neo4jClient(@Qualifier("devDriver") Driver driver,@Qualifier("devDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return Neo4jClient.create(driver, databaseNameProvider);}@Bean@ConfigurationProperties(prefix = "spring.dev.neo4j")public KbNeo4jProperties devNeo4jProperties() {return new KbNeo4jProperties();}/*** The driver to be used for interacting with Neo4j.** @return the Neo4j Java driver instance to work with.*/@Bean("devDriver")@Overridepublic Driver driver() {AuthToken authToken = mapAuthToken(devNeo4jProperties().getAuthentication());Config config = mapDriverConfig(devNeo4jProperties());URI serverUri = determineServerUri(devNeo4jProperties());return GraphDatabase.driver(serverUri, authToken, config);}@Bean("devNeo4jTemplate")@Overridepublic Neo4jTemplate neo4jTemplate(final @Qualifier("devNeo4jClient") Neo4jClient neo4jClient,final Neo4jMappingContext mappingContext,@Qualifier("devDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return new Neo4jTemplate(neo4jClient, mappingContext, databaseNameProvider);}@Bean("devTransactionManager")@Overridepublic PlatformTransactionManager transactionManager(@Qualifier("devDriver") Driver driver,@Qualifier("devDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return super.transactionManager(driver, databaseNameProvider);}@Bean("devDatabaseSelectionProvider")@Overrideprotected DatabaseSelectionProvider databaseSelectionProvider() {String database = devNeo4jProperties().getDatabase();return (database != null) ? DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database): DatabaseSelectionProvider.getDefaultSelectionProvider();}@Bean("devNeo4jImportService")public Neo4jImportServiceImpl neo4jImportService(@Qualifier("devDriver") Driver driver) {return new Neo4jImportServiceImpl(driver);}
}

ProdNeo4jConfig.java

import org.neo4j.driver.AuthToken;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.transaction.PlatformTransactionManager;import java.net.URI;@Configuration
@ConditionalOnProperty(prefix = "spring.prod.neo4j", name = "uri")
public class ProdNeo4jConfig extends AbstractMultiNeo4jConfig {@Bean("prodCypherService")public CypherService prodCypherService(@Qualifier("prodNeo4jClient") Neo4jClient neo4jClient) {return new CypherServiceImpl(neo4jClient);}@Bean("prodCypherQueryService")public CypherQueryService prodCypherQueryService(@Qualifier("prodNeo4jClient") Neo4jClient neo4jClient) {return new CypherQueryServiceImpl(neo4jClient);}@Bean("prodNeo4jClient")public Neo4jClient neo4jClient(@Qualifier("prodDriver") Driver driver,@Qualifier("prodDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return Neo4jClient.create(driver, databaseNameProvider);}@Bean@ConfigurationProperties(prefix = "spring.prod.neo4j")public KbNeo4jProperties prodNeo4jProperties() {return new KbNeo4jProperties();}/*** The driver to be used for interacting with Neo4j.** @return the Neo4j Java driver instance to work with.*/@Bean("prodDriver")@Overridepublic Driver driver() {AuthToken authToken = mapAuthToken(prodNeo4jProperties().getAuthentication());Config config = mapDriverConfig(prodNeo4jProperties());URI serverUri = determineServerUri(prodNeo4jProperties());return GraphDatabase.driver(serverUri, authToken, config);}@Bean("prodNeo4jTemplate")@Overridepublic Neo4jTemplate neo4jTemplate(final @Qualifier("prodNeo4jClient") Neo4jClient neo4jClient,final Neo4jMappingContext mappingContext,@Qualifier("prodDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return new Neo4jTemplate(neo4jClient, mappingContext, databaseNameProvider);}@Bean("prodTransactionManager")
//    @Primary@Overridepublic PlatformTransactionManager transactionManager(@Qualifier("prodDriver") Driver driver,@Qualifier("prodDatabaseSelectionProvider") DatabaseSelectionProvider databaseNameProvider) {return super.transactionManager(driver, databaseNameProvider);}@Bean("prodDatabaseSelectionProvider")@Overrideprotected DatabaseSelectionProvider databaseSelectionProvider() {String database = prodNeo4jProperties().getDatabase();return (database != null) ? DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database): DatabaseSelectionProvider.getDefaultSelectionProvider();}@Bean("prodNeo4jImportService")public Neo4jImportServiceImpl neo4jImportService(@Qualifier("prodDriver") Driver driver) {return new Neo4jImportServiceImpl(driver);}
}

DataSourceConfig.java

import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;@Configuration
public class DataSourceConfig {/*** 显式定义与动态数据源关联的事务管理器。* @param dataSource Spring 容器会自动注入由 dynamic-datasource-spring-boot-starter 创建的代理 DataSource Bean。*                   这个代理 DataSource 知道如何根据上下文切换到 dsPrimary 或其他数据源。* @return 标记为 @Primary 的事务管理器*/@Bean("transactionManager") // 使用标准的 "transactionManager" 作为 Bean 名称@Primary // <--- 关键:标记为主要事务管理器public PlatformTransactionManager transactionManager(DataSource dataSource) {// 使用注入的动态数据源代理来创建事务管理器return new DataSourceTransactionManager(dataSource);}// 通常不需要在这里手动配置 DataSource Bean,// dynamic-datasource-spring-boot-starter 会根据 application-dev.yml 中的配置自动完成。
}

相关文章:

解决 Spring Boot 多数据源环境下事务管理器冲突问题(非Neo4j请求标记了 @Transactional 尝试启动Neo4j的事务管理器)

0. 写在前面 到底遇到了什么问题&#xff1f; 简洁版&#xff1a; 在 Oracle 与 Neo4j 共存的多数据源项目中&#xff0c;一个仅涉及 Oracle 操作的请求&#xff0c;却因为 Neo4j 连接失败而报错。根本原因是 Spring 的默认事务管理器错误地指向了 Neo4j&#xff0c;导致不相…...

Oracle日志系统之重做日志和归档日志

Oracle日志系统之重做日志和归档日志 重做日志归档日志 本文讨论Oracle日志系统中对数据恢复非常重要的两个日志&#xff1a;重做日志和归档日志。 重做日志 重做日志&#xff0c;英文名Redo Log&#xff0c;顾名思义&#xff0c;是用来数据重做的&#xff0c;主要使用场景是事…...

Kubernetes》》K8S》》Pod的健康检查

K8s概念总结 》》》Pod的生命周期阶段 Pod的生命周期可以简单描述&#xff1a;首先Pod被创建&#xff0c;紧接着Pod被调度到Node节点进行部署。 Pod是非常忠诚的&#xff0c;一旦被分配到Node节点后&#xff0c;就不会离开这个Node节点&#xff0c;直到它被删除&#xff0c;删除…...

计算机视觉——基于使用 OpenCV 与 Python 实现相机标定畸变校正

概述 相机标定是一种旨在通过确定相机的内参&#xff08;焦距、光学中心、畸变系数&#xff09;和外参&#xff08;相机的位置和方向&#xff09;&#xff0c;提高图像在现实世界中的几何精度的过程。该过程可以纠正相机拍摄的图像中的畸变&#xff0c;使相机能够准确感知现实…...

Python作业4 文本词云统计,生成词云

编写程序&#xff0c;统计两会政府工作报告热词频率&#xff0c;并生成词云。 2025两会政府工作报告 import jieba import wordcloud from collections import Counter import re# 读取文件 with open("gov.txt", "r", encoding"gbk") as f:t …...

Jenkins 2.492.2 LTS 重置管理员密码

文章目录 1. Jenkins 关闭用户认证2. jenkins 修改密码 如果忘记了 Jenkins 的管理员密码的话&#xff0c;也不用担心&#xff0c;只要你有权限访问 Jenkins 的根目录&#xff0c;就可以轻松地重置密码。 1. Jenkins 关闭用户认证 // 查看 jenkins 家目录&#xff08;使用 doc…...

1. python开发小笔记

本文件记录一些实用的python小知识&#xff0c;会一直更新 1. import路径 1.1 python的import搜索路径可以用sys.path查看&#xff1a; import sys print(sys.path) 1.2 python的搜索目录有&#xff1a; 本脚本所在目录环境变量PYTHONPATH指定的目录标准库目录&#xff0c;通…...

【裁判文书网DES3数据解密】逆向分析

点击翻页&#xff0c;出现请求&#xff0c;可以看到请求参数有个ciphertext密文&#xff0c;响应数据也是密文 打上断点&#xff0c;点击翻页&#xff0c;断住 可以看到postData里面的ciphertext已经生成 往前跟栈&#xff0c;可以发现是var ciphertext cipher(); funct…...

探索 JavaScript 中的 Promise 高级用法与实战

在现代 Web 开发中&#xff0c;异步编程已成为不可或缺的一部分。JavaScript 作为 Web 开发的核心语言&#xff0c;提供了多种处理异步操作的方式&#xff0c;其中 Promise 对象因其简洁、强大的特性而备受青睐。本文将深入探讨 Promise 的高级用法&#xff0c;并结合实际案例&…...

【dify实战】agent结合deepseek实现基于自然语言的数据库问答、Echarts可视化展示、Excel报表下载

使用dify agent实现数据库智能问答&#xff0c;echarts可视化展示&#xff0c;excel报表下载 观看视频&#xff0c;您将学会 在dify下如何快速的构建一个agent&#xff0c;来完成数据分析工作&#xff1b;如何在AI的回复中展示可视化的图表&#xff1b;如何在AI 的回复中加入E…...

C++学习:六个月从基础到就业——面向对象编程:接口设计

C学习&#xff1a;六个月从基础到就业——面向对象编程&#xff1a;接口设计 本文是我C学习之旅系列的第十五篇技术文章&#xff0c;重点讨论在C中进行接口设计的原则、技术和最佳实践。查看完整系列目录了解更多内容。 引言 在面向对象的软件开发中&#xff0c;良好的接口设计…...

花园灌溉问题

#include <bits/stdc.h> using namespace std;// 设置最大行列数&#xff08;题目限制 n, m ≤ 100&#xff09; const int N 104;// 标记某个格子是否已经被水浇灌 bool used[N][N];// 队列&#xff0c;用于 BFS&#xff0c;存储当前水源的位置 queue<pair<int,i…...

《AI大模型应知应会100篇》第22篇:系统提示词(System Prompt)设计与优化

第22篇&#xff1a;系统提示词(System Prompt)设计与优化 摘要 在大语言模型&#xff08;LLM&#xff09;应用中&#xff0c;系统提示词&#xff08;System Prompt&#xff09;是控制模型行为的核心工具之一。它不仅定义了模型的身份、角色和行为规范&#xff0c;还直接影响输…...

Jsp技术入门指南【六】jsp脚本原理及隐式对象

Jsp技术入门指南【六】jsp脚本原理及隐式对象 前言一、JSP 脚本元素1.1 声明1.2 表达式1.3 脚本标签 二、JSP 的隐式对象是什么三、隐式对象详解outrequestsessionapplicationconfigexception 前言 在之前的博客中&#xff0c;我们已经介绍了JSP的环境搭建、编译文件查找以及生…...

transient关键字深度解析

Java transient 关键字深度解析 1. 核心概念 (1) 基本定义 作用:标记字段不参与序列化 适用场景: 敏感数据(如密码、密钥) 临时计算字段 依赖运行时环境的字段(如Thread对象) (2) 语法示例 java public class User implements Serializable {private String username…...

Jsp技术入门指南【五】详细讲解jsp结构页面

Jsp技术入门指南【五】详细讲解jsp结构页面 前言一、JSP页面的结构二、JSP页面的部件1. 指令&#xff08;核心控制部件&#xff09;2. 动作&#xff08;页面交互部件&#xff0c;了解即可&#xff09;3. 脚本&#xff08;Java逻辑嵌入部件&#xff09; 三、JSP指令详解1.1 JSP指…...

Beyond Compare 30天评估到期 解决方法

Beyond Compare 30天评估到期 解决方法 一、问题二、解决办法2.1 第一步&#xff1a;打开注册表2.2 第二步&#xff1a;删除cacheID 三、效果 一、问题 Beyond Compare提示评估到期&#xff0c;重装也无效&#xff0c;只需简单两步&#xff0c;轻轻松松出困境。 二、解决办法…...

探索蓝桥杯:嵌入式开发技巧分享与实践

在信息技术飞速发展的今天&#xff0c;嵌入式系统作为物联网和智能设备的核心技术之一&#xff0c;正扮演着愈发重要的角色。蓝桥杯作为国内知名的科技竞赛平台&#xff0c;为广大学生和科技爱好者提供了展示自己嵌入式开发能力的舞台。在这场竞赛中&#xff0c;参赛者不仅需要…...

Arduino无线体感机器手——问题汇总

文章不介绍具体参数&#xff0c;有需求可去网上搜索。 特别声明&#xff1a;不论年龄&#xff0c;不看学历。既然你对这个领域的东西感兴趣&#xff0c;就应该不断培养自己提出问题、思考问题、探索答案的能力。 提出问题&#xff1a;提出问题时&#xff0c;应说明是哪款产品&a…...

学习设计模式《一》——简单工厂

一、基础概念 1.1、接口 简单的说&#xff1a;接口是【用来实现类的行为定义、约束类的行为】&#xff08;即&#xff1a;定义可以做什么&#xff09;&#xff1b;接口可以包含【实例方法】、【属性】、【事件】、【索引器】或这四种成员类型的任意组合。 接口的优点&#xff1…...

python有序列表

您的代码整体结构良好&#xff0c;但存在一些关键错误和优化点。以下是对代码的详细评价及改进建议&#xff1a;---### 主要问题1. **add方法中的链表断裂问题**- **问题描述**&#xff1a;当向链表中间插入节点时&#xff0c;未正确设置新节点的next&#xff0c;导致后续节点丢…...

使用Lombok @Builder 收参报错提示没有无参构造方法的原因与解决办法

使用Lombok Builder 收参报错提示没有无参构造方法的原因与解决办法 类上加了Builder之后接口接收前端传来的参数报错&#xff1a;(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) 1.解决办法…...

010数论——算法备赛

数论 模运算 一般求余都是对正整数的操作&#xff0c;如果对负数&#xff0c;不同编程语言结果可能不同。 C/javapythona>m,0<a%m<m-1 a<m,a%ma~5%32~-5%3 -21(-5)%(-3) -2~5%(-3)2-1正数&#xff1a;&#xff08;ab&#xff09;%m((a%m)(b%m))%m~正数&#xff…...

NAT、代理服务、内网穿透

NAT、代理服务、内网穿透 1、NAT1.1、NAT过程1.2、NAPT2、内网穿透3、内网打洞3、代理服务器3.1、正向代理3.2、反向代理1、NAT 1.1、NAT过程 之前我们讨论了IPv4协议中IP地址数量不充足的问题。NAT技术是当前解决IP地址不够用的主要手段,是路由器的一个重要功能。 NAT能够将…...

C# 点击导入,将需要的参数传递到弹窗的页面

点击导入按钮&#xff0c;获取本页面的datagridview标题的结构&#xff0c;并传递到导入界面。 新增一个datatable用于存储datagridview的caption和name&#xff0c;这里用的是devexpress组件中的gridview。 DataTable dt new DataTable(); DataColumn CAPTION …...

Linux 文件查找终极指南:find, locate, grep 等命令详解

在 Linux 系统管理和日常使用中,文件查找是一项不可或缺的基本技能。无论是寻找配置文件、查找日志文件中的特定错误,还是清理旧的临时文件,掌握高效的文件查找工具都能让你事半功倍。Linux 提供了多种强大的命令行工具来满足不同的查找需求。本文将详细介绍几个最常用、最强…...

嵌入式硬件常用总线接口知识体系总结和对比

0.前言 在嵌入式工程实现中,多多少少我们都使用过总线,各种各样的总线应用于不同场合,不同场景有不同的优势,但是我们在作为工程师过程中在如何选择项目合适的总线,根据什么来选?需要我们对项目全局和总线特征有所了解,本文目的就是对比多种总线的关键特征 我们在聊到…...

【unity实战】Unity动画层级(Animation Layer)的Sync同步和Timing定时参数使用介绍,同步动画层制作角色的受伤状态

文章目录 前言方案一&#xff1a;复制粘贴原有层级的状态机1、实现2、问题 方法二&#xff1a;勾选Sync同步动画层1、简单实现同步2、同步blend tree的问题3、动画状态的播放时长4、下层状态覆盖了上层状态 专栏推荐完结 前言 如何制作角色的受伤状态&#xff1f; 玩家角色在…...

Uniapp调用native.js使用经典蓝牙串口通讯方法及问题解决

本人尝试在uniapp环境下开发一款安卓应用&#xff0c;需要与使用经典蓝牙协议的设备进行串口通讯&#xff0c;而uniapp官方给出的蓝牙操作接口目前只支持BLE&#xff08;低功耗蓝牙&#xff09;&#xff0c;用该接口无法正常获取到我想要连接的设备。 通过大量搜索&#xff0c…...

C++23 新特性:行拼接前去除空白符 (P2223R2)

文章目录 1\. 什么是行拼接前去除空白符2\. 为什么需要这一特性3\. 示例代码输出结果 4\. 编译器支持5\. 优势与应用场景5.1 提高代码可读性5.2 减少潜在错误5.3 适用于多行字符串 6\. 其他相关特性7\. 总结 C 语言一直在不断进化&#xff0c;以满足现代软件开发的需求。C23 标…...