解決 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 中的配置自動完成。
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901895.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901895.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901895.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

理解和實現RESTful API的最佳實踐

理解和實現RESTful API的最佳實踐 在當今數字化時代&#xff0c;APIs已成為軟件開發的核心組件&#xff0c;而RESTful API以其簡潔、靈活和可擴展性成為最流行的API設計風格。本文將深入探討RESTful API的概念、特點和實施指南&#xff0c;幫助開發者構建高效、可靠的Web服務。…

大語言模型微調技術與實踐:從原理到應用

大語言模型微調技術與實踐&#xff1a;從原理到應用 摘要&#xff1a;隨著大語言模型&#xff08;LLM&#xff09;技術的迅猛發展&#xff0c;預訓練語言模型在各種自然語言處理任務中展現出強大的能力。然而&#xff0c;將這些通用的預訓練模型直接應用于特定領域或任務時&am…

遨游科普:三防平板除了三防特性?還能實現什么功能?

在工業4.0浪潮席卷全球的今天&#xff0c;電子設備的功能邊界正經歷著革命性突破。三防平板電腦作為"危、急、特"場景的智能終端代表&#xff0c;其價值早已超越防水、防塵、防摔的基礎防護屬性。遨游通訊通過系統級技術創新&#xff0c;將三防平板打造為集通信中樞、…

前端實戰:基于 Vue 與 QRCode 庫實現動態二維碼合成與下載功能

在現代 Web 應用開發中&#xff0c;二維碼的應用越來越廣泛&#xff0c;從電子票務到信息傳遞&#xff0c;它都扮演著重要角色。本文將分享如何在 Vue 項目中&#xff0c;結合QRCode庫實現動態二維碼的生成、與背景圖合成以及圖片下載功能&#xff0c;打造一個完整且實用的二維…

HAL詳解

一、直通式HAL 這里使用一個案例來介紹直通式HAL&#xff0c;選擇MTK的NFC HIDL 1.0為例&#xff0c;因為比較簡單&#xff0c;代碼量也比較小&#xff0c;其源碼路徑&#xff1a;vendor/hardware/interfaces/nfc/1.0/ 1、NFC HAL的定義 1&#xff09;NFC HAL數據類型 通常定…

Vue自定義指令-防抖節流

Vue2版本 // 防抖 // <el-button v-debounce"[reset,click,300]" ></el-button> // <el-button v-debounce"[reset]" ></el-button> Vue.directive(debounce, { inserted: function (el, binding) { let [fn, event "cl…

AI知識補全(十六):A2A - 谷歌開源的agent通信協議是什么?

名人說&#xff1a;一笑出門去&#xff0c;千里落花風。——辛棄疾《水調歌頭我飲不須勸》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;AI知識補全&#xff08;十五&#xff09;&#xff1a;AI可解…

【機器人創新創業應需明確產品定位與方向指南】

機器人領域的創新創業, 需要對公司和產品的定位和生態進行深入思考, 明確其定位與發展目標, 明確產品在是為G、為B還是為C進行服務。 本文引用地址&#xff1a;https://www.eepw.com.cn/article/202504/469401.htm 超前的、探索性的創新技術一般是面向G端, 而不是面向B端或者C…

網安加·百家講壇 | 劉志誠:AI安全風險與未來展望

作者簡介&#xff1a;劉志誠&#xff0c;樂信集團信息安全中心總監、OWASP廣東區域負責人、網安加社區特聘專家。專注于企業數字化過程中網絡空間安全風險治理&#xff0c;對大數據、人工智能、區塊鏈等新技術在金融風險治理領域的應用&#xff0c;以及新技術帶來的技術風險治理…

TOA與AOA聯合定位的高精度算法,三維、4個基站的情況,MATLAB例程,附完整代碼

本代碼實現了三維空間內目標的高精度定位,結合到達角(AOA) 和到達時間(TOA) 兩種測量方法,通過4個基站的協同觀測,利用最小二乘法解算目標位置。代碼支持噪聲模擬、誤差分析及三維可視化,適用于無人機導航、室內定位等場景。訂閱專欄后可獲得完整代碼 文章目錄 運行結果…

2025MathorcupC題 音頻文件的高質量讀寫與去噪優化 保姆級教程講解|模型講解

2025Mathorcup數學建模挑戰賽&#xff08;媽媽杯&#xff09;C題保姆級分析完整思路代碼數據教學 C題&#xff1a;音頻文件的高質量讀寫與去噪優化 隨著數字媒體技術的迅速發展&#xff0c;音頻處理成為信息時代的關鍵技術之一。在日常生活中&#xff0c;從錄音設備捕捉的原始…

Deno Dep:顛覆傳統的模塊化未來

一、重新定義依賴管理&#xff1a;Deno Dep 的革新哲學 Deno Dep&#xff08;原Deno包管理器&#xff09;徹底重構了JavaScript/TypeScript的依賴管理方式&#xff0c;其核心突破體現在&#xff1a; 1. 瀏覽器優先的模塊化&#xff08;URL-Centric Modules&#xff09; // 直…

歐拉系統升級openssh 9.7p1

開發的系統準備上線&#xff0c;甲方對歐拉服務器進行了掃描&#xff0c;發現openssh版本為8.2p1&#xff0c;存在漏洞&#xff0c;因此需要升級openssh至9.7p1。歐拉系統版本為20.03 SP3。 1、下載openssh 9.7p1 https://www.openssh.com/releasenotes.html&#xff0c; 將下…

如何精通C++編程?

如果從學生時代算起的話&#xff0c;我學習和使用C已經差不多快十年了&#xff0c;仍然不敢說自己已經掌握了C的全部特性&#xff0c;但或許能夠給出一些有用的建議吧。 我學習C全靠自學&#xff0c;花費了不少的功夫&#xff0c;在這里分享一些學習心得&#xff0c;希望對大家…

提高Qt工作線程的運行速度

1. 使用線程池&#xff08;QThreadPool&#xff09;替代單一線程 做過&#xff0c;但是當時沒想到。。。 目的&#xff1a;減少線程創建和銷毀的開銷&#xff0c;復用線程資源。 實現步驟&#xff1a; 創建自定義任務類&#xff1a;繼承QRunnable&#xff0c;實現run()方法。…

Solon AI MCP Server 入門:Helloworld (支持 java8 到 java24。國產解決方案)

目前網上能看到的 MCP Server 基本上都是基于 Python 或者 nodejs &#xff0c;雖然也有 Java 版本的 MCP SDK&#xff0c;但是鮮有基于 Java 開發的。 作為Java 開發中的國產頂級框架 Solon 已經基于 MCP SDK 在進行 Solon AI MCP 框架開發了&#xff0c;本文將使用 Solon AI …

STL之迭代器(iterator)

迭代器的基本概念 迭代器(iterator)模式又稱為游標(Cursor)模式&#xff0c;用于提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。或者這樣說可能更容易理解&#xff1a;Iterator模式是運用于聚合對象的一種模式&#xff0c;通過運用該模式&#…

Android系統通知機制深度解析:Framework至SystemUI全鏈路剖析

1. 前言 在Android 13的ROM定制化開發中&#xff0c;系統通知機制作為用戶交互的核心組件&#xff0c;其實現涉及Framework層到SystemUI的復雜協作。本文將深入剖析從Notification發送到呈現的全鏈路流程&#xff0c;重點解析關鍵類的作用機制及系統服務間的交互邏輯&#xff…

UE5角色狀態機中跳躍落地移動銜接問題

UE5系列文章目錄 文章目錄 UE5系列文章目錄前言一、狀態機設置二、主要藍圖 前言 先說說遇到的問題&#xff0c;在我按空格鍵跳躍落地以后&#xff0c;角色落地再按WSAD鍵移動就出現了畫面中角色抽搐的情況 一、狀態機設置 在Unreal Engine 5中創建角色時&#xff0c;處理跳…

使用SVM對心臟數據是否患病進行分類預測

作者簡介 杜嘉寶&#xff0c;男&#xff0c;西安工程大學電子信息學院&#xff0c;2024級研究生 研究方向&#xff1a;變壓器故障預警與檢測 電子郵件&#xff1a;djb857497378gmail.com 王子謙&#xff0c;男&#xff0c;西安工程大學電子信息學院&#xff0c;2024級研究生&a…