【SpringBoot Druid Mysql多数据源整合】

SpringBoot Druid Mysql多数据源整合

  • 一、背景
  • 二、配置结果
    • 2.1 SpringBoot java 类配置
      • 2.1.1 启动类配置
      • 2.1.2 java Config配置
    • 2.2 SpringBoot yml 配置
  • 三、mybatis插件配置
    • 3.1 PageHelper的yml配置
    • 3.2 mybatis设置自定义字段默认值
  • 四、配置解释

一、背景

  • 公司项目需要连接另外一个数据库来处理数据

  • 处理方法其实很多,如下所示:

    1. 给这个数据库单独跑一个服务,用来查询数据
    2. 直接将该数据库表同步到本地服务数据库
    3. 在本地服务中直接配置多数据源用来查询数据
  • 其实每种方法都有自己的利弊,由于各种原因还是选择了方法3,配置多数据源进行查询

  • SpringBoot版本 2.3.12.RELEASE

  • Druid版本

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.22</version>
</dependency>
  • 其他mysql,mybatis都是正常配置

二、配置结果

2.1 SpringBoot java 类配置

2.1.1 启动类配置

@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})
@ServletComponentScan
@EnableCaching
public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);}}
  • 其中使用@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class})的原因见1

2.1.2 java Config配置

  • 需要建立3个java类,DruidAutoConfiguration.java,DruidConfigTestOne.java,DruidConfigTestTwo.java
  • DruidAutoConfiguration作用见2
  • DruidConfigTestOne作用见3
  • DruidConfigTestTwo作用见4
@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DruidStatProperties.class)
@Import({DruidSpringAopConfiguration.class,DruidStatViewServletConfiguration.class,DruidWebStatFilterConfiguration.class,DruidFilterConfiguration.class})
public class DruidAutoConfiguration {
}
@Configuration
@MapperScan(basePackages = DruidConfigTestOne.PACKAGE, sqlSessionTemplateRef  = "testOneSqlSessionTemplate")
public class DruidConfigTestOne {/*** mapper 所在包* 这个地方需要注意xml文件要在resources目录com/test/one/mapper下,mapper java类在com.test.one.mapper包下,这样就不需要配置xml文件所在位置,否则需要在sqlSessionFactory上面新增mapperLocation的配置* bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/com/test/one/mapper/*.xml"));*/protected static final String PACKAGE = "com.test.one.mapper";/*** 配置自定义数据源,一定要切记,在SpringBoot启动类上去掉DruidDataSourceAutoConfigure.class** @return javax.sql.DataSource* @author liulin* @date 2025/4/11 16:49*/@Bean("testOneDataSource")@ConfigurationProperties(prefix = "spring.datasource.druid.test-one")@Primarypublic DataSource testOneDataSource(){return DruidDataSourceBuilder.create().build();}/*** 创建并配置一个SqlSessionFactory实例* 该方法使用Spring框架的@Bean注解,表明该方法会返回一个SqlSessionFactory对象,该对象将被Spring容器管理** @param dataSource 数据源,通过该参数指定SqlSessionFactory将要使用的数据库连接* @return SqlSessionFactory 一个配置好的SqlSessionFactory实例,用于创建SqlSession* @throws Exception 如果创建过程中出现错误,将抛出异常*/@Bean(name = "testOneSqlSessionFactory")@Primarypublic SqlSessionFactory sqlSessionFactory(@Qualifier("testOneDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean.getObject();}/*** 创建一个数据源事务管理器* <p/>* 该方法定义了一个Spring的@Bean注解,用于创建一个DataSourceTransactionManager实例* 这个实例用于管理与数据源相关的事务这个方法被标记为@Primary,意味着在相同类型* 的多个Bean存在时,Spring会默认选择这个Bean** @param dataSource 数据源实例,用于事务管理器的构造* @return DataSourceTransactionManager实例,用于管理数据库事务*/@Bean(name = "testOneTransactionManager")@Primarypublic DataSourceTransactionManager transactionManager(@Qualifier("testOneDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}/*** 创建并配置一个SqlSessionTemplate实例* 该实例用于执行SQL操作,利用Spring框架的依赖注入功能进行管理** @param sqlSessionFactory 用于创建SqlSessionTemplate的工厂,通过资格器@Qualifier指定特定的工厂* @return 返回配置好的SqlSessionTemplate实例,用于执行数据库操作* @throws Exception 如果实例化过程中遇到任何问题,则抛出异常*/@Bean(name = "testOneSqlSessionTemplate")@Primarypublic SqlSessionTemplate sqlSessionTemplate(@Qualifier("testOneSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}
@Configuration
@MapperScan(basePackages = DruidConfigTestTwo.PACKAGE, sqlSessionTemplateRef  = "testTwoSqlSessionTemplate")
public class DruidConfigTestTwo {/*** mapper 所在包*/protected static final String PACKAGE = "com.test.two.mapper";/*** 配置自定义数据源,一定要切记,在SpringBoot启动类上去掉DruidDataSourceAutoConfigure.class** @return javax.sql.DataSource* @author liulin* @date 2025/4/11 16:49*/@Bean("testTwoDataSource")@ConfigurationProperties(prefix = "spring.datasource.druid.test-two")public DataSource testTwoDataSource(){return DruidDataSourceBuilder.create().build();}/*** 创建并配置一个SqlSessionFactory实例* 该方法使用Spring框架的@Bean注解,表明该方法会返回一个SqlSessionFactory对象,该对象将被Spring容器管理** @param dataSource 数据源,通过该参数指定SqlSessionFactory将要使用的数据库连接* @return SqlSessionFactory 一个配置好的SqlSessionFactory实例,用于创建SqlSession* @throws Exception 如果创建过程中出现错误,将抛出异常*/@Bean(name = "testTwoSqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier("testTwoDataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean.getObject();}/*** 创建一个数据源事务管理器* <p/>* 该方法定义了一个Spring的@Bean注解,用于创建一个DataSourceTransactionManager实例* 这个实例用于管理与数据源相关的事务这个方法被标记为@Primary,意味着在相同类型* 的多个Bean存在时,Spring会默认选择这个Bean** @param dataSource 数据源实例,用于事务管理器的构造* @return DataSourceTransactionManager实例,用于管理数据库事务*/@Bean(name = "testTwoTransactionManager")public DataSourceTransactionManager transactionManager(@Qualifier("testTwoDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}/*** 创建并配置一个SqlSessionTemplate实例* 该实例用于执行SQL操作,利用Spring框架的依赖注入功能进行管理** @param sqlSessionFactory 用于创建SqlSessionTemplate的工厂,通过资格器@Qualifier指定特定的工厂* @return 返回配置好的SqlSessionTemplate实例,用于执行数据库操作* @throws Exception 如果实例化过程中遇到任何问题,则抛出异常*/@Bean(name = "testTwoSqlSessionTemplate")public SqlSessionTemplate sqlSessionTemplate(@Qualifier("testTwoSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}
}

2.2 SpringBoot yml 配置

  • yml 配置原因见5
spring:datasource:# 这个配置可要可不要,意义不大type: com.alibaba.druid.pool.DruidDataSourcedruid:# Spring监控aop-patterns: com.test.one.service.*,com.test.two.service.*# 监控配置web-stat-filter:# 是否启用StatFilter默认值trueenabled: true# 添加过滤规则url-pattern: /*# 忽略过滤的格式exclusions: /druid/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico# 关闭session监控session-stat-enable: false# Druid内置提供了一个StatViewServlet用于展示Druid的统计信息stat-view-servlet:# 是否启用StatViewServlet默认值trueenabled: true# 访问路径为/druid时,跳转到StatViewServleturl-pattern: /druid/*# 是否能够重置数据reset-enable: false# 需要账号密码才能访问控制台,默认为rootlogin-username: testlogin-password: test# IP白名单allow:# IP黑名单(共同存在时,deny优先于allow)deny:test-one:url: jdbc:mysql://127.0.0.1:3306/test_one?useSSL=false&characterEncoding=utf8&useTimezone=true&serverTimezone=GMT%2B8username: rootpassword: '123456'driver-class-name: com.mysql.cj.jdbc.Driver# 初始化时建立物理连接的个数initial-size: 5# 连接池的最小空闲数量min-idle: 5# 连接池最大连接数量max-active: 200# 获取连接时最大等待时间,单位毫秒max-wait: 60000# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true# 既作为检测的间隔时间又作为testWhileIdel执行的依据time-between-eviction-runs-millis: 60000# 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接(配置连接在池中的最小生存时间)min-evictable-idle-time-millis: 30000# 用来检测数据库连接是否有效的sql 必须是一个查询语句(oracle中为 select 1 from dual)validation-query: select 1# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-borrow: false# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-return: false# 是否缓存preparedStatement, 也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。pool-prepared-statements: false# 置监控统计拦截的filters,去掉后监控界面sql无法统计,stat: 监控统计、Slf4j:日志记录、waLL: 防御sqL注入filters: stat,wall,slf4j# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100max-pool-prepared-statement-per-connection-size: -1# 合并多个DruidDataSource的监控数据use-global-data-source-stat: true# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000test-two:url: jdbc:mysql://127.0.0.1:3306/test_two?useSSL=false&characterEncoding=utf8&useTimezone=true&serverTimezone=GMT%2B8username: rootpassword: '123456'driver-class-name: com.mysql.cj.jdbc.Driver# 初始化时建立物理连接的个数initial-size: 5# 连接池的最小空闲数量min-idle: 5# 连接池最大连接数量max-active: 200# 获取连接时最大等待时间,单位毫秒max-wait: 60000# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true# 既作为检测的间隔时间又作为testWhileIdel执行的依据time-between-eviction-runs-millis: 60000# 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接(配置连接在池中的最小生存时间)min-evictable-idle-time-millis: 30000# 用来检测数据库连接是否有效的sql 必须是一个查询语句(oracle中为 select 1 from dual)validation-query: select 1# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-borrow: false# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为truetest-on-return: false# 是否缓存preparedStatement, 也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。pool-prepared-statements: false# 置监控统计拦截的filters,去掉后监控界面sql无法统计,stat: 监控统计、Slf4j:日志记录、waLL: 防御sqL注入filters: stat,wall,slf4j# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100max-pool-prepared-statement-per-connection-size: -1# 合并多个DruidDataSource的监控数据use-global-data-source-stat: true# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

三、mybatis插件配置

3.1 PageHelper的yml配置

  • yml配置原因见6
#分页插件配置
pagehelper:helper-dialect: mysqlreasonable: truesupport-methods-arguments: trueparams: count=countSql

3.2 mybatis设置自定义字段默认值

  • 需要2个java类,MyBatisInterceptorConfig.java,SetMySqlValueAutoConfiguration.java
  • MyBatisInterceptorConfig见原因7
  • SetMySqlValueAutoConfiguration见原因8
@Slf4j
@SuppressWarnings("unchecked")
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class MyBatisInterceptorConfig implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];// 获取 SQL 命令SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();// 获取参数Object parameter = invocation.getArgs()[1];// 如果不存在参数,直接返回if (parameter == null) {return invocation.proceed();}// 如果是批量插入一般是List类型,包装在ParamMap中if (parameter instanceof MapperMethod.ParamMap) {MapperMethod.ParamMap<Object> paramMap = (MapperMethod.ParamMap<Object>) parameter;for (Map.Entry<String, Object> entry : paramMap.entrySet()) {Object paramValue = entry.getValue();if (paramValue instanceof List) {List<Object> list = (List<Object>) paramValue;for (Object value : list) {// 设置对应数据值setFieldValues(value, sqlCommandType);}break;}}} else {setFieldValues(parameter, sqlCommandType);}return invocation.proceed();}/*** 设置字段对应值** @param parameter 实体信息* @param sqlCommandType sql类型* @author liulin* @date 2024-04-22 16:32:39**/private void setFieldValues(Object parameter, SqlCommandType sqlCommandType) throws IllegalAccessException, InvocationTargetException {// 获取私有成员变量Method[] declaredMethods = parameter.getClass().getDeclaredMethods();for (Method method : declaredMethods) {if (SqlCommandType.INSERT.equals(sqlCommandType)) {String name = method.getName();switch (name) {case "setUpdateUser":case "setCreateUser":method.invoke(parameter, getCurrentUserId());break;case "setCreateTime":case "setUpdateTime":method.invoke(parameter, new Date());break;case "setUpdateUserType":case "setCreateUserType":method.invoke(parameter, getCurrentUserType());break;default:break;}} else if (SqlCommandType.UPDATE.equals(sqlCommandType)) {String name = method.getName();switch (name) {case "setUpdateUser":method.invoke(parameter, getCurrentUserId());break;case "setUpdateTime":method.invoke(parameter, new Date());break;case "setUpdateUserType":method.invoke(parameter, getCurrentUserType());break;default:break;}}}}/*** 获取当前用户类型** @return int* @author liulin* @date 2024-11-14 15:05:55**/private Integer getCurrentUserType() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null) {return null;}Object principal = authentication.getPrincipal();if (principal instanceof CarfiSessionUser) {return 1;}return null;}/*** 获取当前用户id** @return String* @author liulin* @date 2024-04-22 13:42:37**/private String getCurrentUserId() {Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null) {return null;}Object principal = authentication.getPrincipal();if (principal instanceof CarfiSessionUser) {return CarfiUserUtils.getSysUser().getUserId();}return null;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// comment explaining why the method is empty}
}
@Configuration
@ConditionalOnBean({SqlSessionFactory.class})
@AutoConfigureAfter({MybatisAutoConfiguration.class})
@Lazy(false)
public class SetMySqlValueAutoConfiguration implements InitializingBean {@Resourceprivate List<SqlSessionFactory> sqlSessionFactoryList;@Overridepublic void afterPropertiesSet() throws Exception {MyBatisInterceptorConfig interceptor = new MyBatisInterceptorConfig();for (SqlSessionFactory sqlSessionFactory : this.sqlSessionFactoryList) {org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();if (!this.containsInterceptor(configuration, interceptor)) {configuration.addInterceptor(interceptor);}}}private boolean containsInterceptor(org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {try {return configuration.getInterceptors().contains(interceptor);} catch (Exception var4) {return false;}}
}

四、配置解释


  1. DruidDataSourceAutoConfigure

    • 为什么要在启动类上排除DruidDataSourceAutoConfigure,是因为这个配置类com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure是下面这个样子在这里插入图片描述
    • 它自动装配了一堆druid的默认配置,包括数据源,监控界面,druid AOP切面等等类,其中DataSourceProperties导致spring.datasource下面必须要有默认数据库配置,否则就会报错,所以其实这里可以弄一个主数据源放上去,当然意义不是很大。
    ↩︎
  2. DruidAutoConfiguration

    • 因为我排除了DruidDataSourceAutoConfigure,所以必须要把监控界面,druid AOP切面等等重新引入,否则druid的监控界面就没法正常使用了,druid监控界面进入路径: http://127.0.0.1:8080/login.html
    ↩︎
  3. DruidConfigTestOne

    • 这个就很简单咯,就是配置数据源,sqlSessionFactory,事务管理器等一堆和数据配置有关的,@Primary保证是主数据源加载
    ↩︎
  4. DruidConfigTestTwo

    • 和DruidConfigTestOne作用一致,就是副数据源
    ↩︎
  5. Druid 的 yml配置

    • yml为什么可以像我上面这么配置,其实主要还是看DruidDataSourceAutoConfigure,他里面@EnableConfigurationProperties,@Import都可以点进去,可以看里面的字段属性,实际与yml的配置相关
    ↩︎
  6. PageHelper的yml配置

    • 这个主要见PageHelperAutoConfiguration.java,com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration在这里插入图片描述
    • 可以看到实现了InitializingBean,并且在afterPropertiesSet方法中设置了拦截器PageInterceptor,com.github.pagehelper.PageInterceptor
    ↩︎
  7. MyBatisInterceptorConfig

    • 这个没啥好说的,就是在新增,更新时自动注入一些自定义字段值
    ↩︎
  8. SetMySqlValueAutoConfiguration

    • 这个是因为MybatisAutoConfiguration.java类,org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中的sqlSessionFactory被我自定义的sqlSessionFactory干扰了导致无法实现mybatis的拦截器注入,所以我就仿照PageHelperAutoConfiguration实现了一次自动注入,这样mybatis的自定义拦截器就不会因为自定义sqlSessionFactory而失效了。MybatisAutoConfiguration的sqlSessionFactory是下面这样的在这里插入图片描述
    ↩︎

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

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

相关文章

GGML源码逐行调试(中)

目录 前言1. 简述2. 加载模型超参数3. 加载词汇表4. 初始化计算上下文5. 初始化计算后端6. 创建模型张量7. 分配缓冲区8. 加载模型权重结语下载链接参考 前言 学习 UP 主 比飞鸟贵重的多_HKL 的 GGML源码逐行调试 视频&#xff0c;记录下个人学习笔记&#xff0c;仅供自己参考&…

kubectl的使用

查看集群有多少节点 kubectl get nodes 获取集群状态的摘要信息&#xff08;组件信息&#xff09; kubectl get cs 查看所有命名空间下的所有pod的状态和信息 kubectl get pods --all-namespaces 查看所有命名空间的状态和信息 kubectl get namespaces /ns 查看kube-system…

git在分支上会退到某个指定的commit

1、在idea上先备份好分支&#xff08;基于现有分支new branch&#xff09; 2、在gitlab管理端删除现有分支 3、在idea中大卡terminal&#xff0c;执行 git log 查看commit log ,找到要会退到的commit唯一码&#xff0c;然后执行git reset 唯一码 4、查看本地代码状态 git st…

动态路由, RIP路由协议,RIPv1,RIPv2

动态路由 1、回顾 路由&#xff1a;从源主机到目标主机的过程 源主机发送数据给目标主机&#xff0c;源主机会查看自身的路由信息 如果目标主机是自己同网段&#xff0c;源主机查看的是直连路由 如果目标主机和自己不同网段&#xff0c;源主机查看的是静态路由、动态路由、默…

前端面试-工程化(webpack、vite)

Webpack 相关问题&#xff08;25道&#xff09; Webpack 的核心概念有哪些&#xff1f;&#xff08;Entry、Output、Loader、Plugin、Module、Bundle&#xff09;如何配置 Webpack 的多入口和多出口&#xff1f;Webpack 的 Tree Shaking 实现原理是什么&#xff1f;Loader 和 …

idea 2024 build菜单不见了

Q如题 idea 2024 新版UI添加build和recompile菜单 A如图&#xff0c;右键顶部栏之后&#xff0c;点击Add to Main Toolbar菜单&#xff0c;在里面就能找到Build菜单&#xff0c;添加接口。 Recompile菜单的话在Customize Toolbar中搜索添加才行。

【开源项目】Excel手撕AI算法深入理解(三):时序(RNN、mamba)

项目源码地址&#xff1a;https://github.com/ImagineAILab/ai-by-hand-excel.git 一、RNN 1. RNN 的核心思想 RNN 的设计初衷是处理序列数据&#xff08;如时间序列、文本、语音&#xff09;&#xff0c;其核心特点是&#xff1a; 隐藏状态&#xff08;Hidden State&#xff…

pycharm已有python3.7,如何新增Run Configurations中的Python interpreter为python 3.9

在 PyCharm 中&#xff0c;如果你已经安装了 Python 3.9&#xff0c;并且希望在 Run Configurations 中新增一个 Python 3.9 的解释器&#xff0c;可以按照以下步骤操作&#xff1a; 步骤 1&#xff1a;打开 PyCharm 设置 点击 PyCharm 左上角的 File 菜单。选择 Settings&am…

【H桥电机驱动电路原理】-学习笔记

工作原理 电路分析 这是一个由晶体管构成的 H 桥电机驱动电路 &#xff0c;以下是对其各部分的介绍&#xff1a; 核心器件 晶体管&#xff1a;电路中使用了 PNP 型的 SS8550&#xff08;Q5、Q6 &#xff09;和 NPN 型的 SS8050&#xff08;Q9、Q10、Q13、Q14 &#xff09;。…

【家政平台开发(49)】解锁家政平台上线密码:服务器选型与配置全攻略

本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,…

驱动开发硬核特训 · Day 10 (理论上篇):设备模型 ≈ 运行时的适配器机制

&#x1f50d; B站相应的视屏教程&#xff1a; &#x1f4cc; 内核&#xff1a;博文视频 - 总线驱动模型实战全解析 敬请关注&#xff0c;记得标为原始粉丝。 在 Linux 驱动开发中&#xff0c;设备模型&#xff08;Device Model&#xff09;是理解驱动架构的核心。而从软件工程…

arm_math.h、arm_const_structs.h 和 arm_common_tables.h

在 ​​FOC&#xff08;Field-Oriented Control&#xff0c;磁场定向控制&#xff09;​​ 中&#xff0c;arm_math.h、arm_const_structs.h 和 arm_common_tables.h 是 CMSIS-DSP 库的核心组件&#xff0c;用于实现高效的数学运算、预定义结构和查表操作。以下是它们在 FOC 控…

Android: gradient 使用

在 Android 中使用 gradient&#xff08;渐变&#xff09; 通常是通过 drawable 文件来设置背景。下面是可以直接用的几种用法汇总&#xff0c;包括线性渐变、径向渐变、扫描渐变&#xff08;sweep&#xff09;等&#xff1a; ✅ 1. Linear Gradient&#xff08;线性渐变&#…

打造AI应用基础设施:Milvus向量数据库部署与运维

目录 打造AI应用基础设施&#xff1a;Milvus向量数据库部署与运维1. Milvus介绍1.1 什么是向量数据库&#xff1f;1.2 Milvus主要特点 2. Milvus部署方案对比2.1 Milvus Lite2.2 Milvus Standalone2.3 Milvus Distributed2.4 部署方案对比表 3. Milvus部署操作命令实战3.1 Milv…

AI Agent 在医疗健康领域的深度应用剖析

引言 随着人工智能技术的迅猛发展&#xff0c;AI Agent 在医疗健康领域展现出了巨大的应用潜力。它犹如一位智能助手&#xff0c;凭借其强大的数据处理和分析能力&#xff0c;渗透到医疗健康的各个环节&#xff0c;从疾病诊断、治疗方案制定到患者康复监控&#xff0c;都发挥着…

树莓派超全系列教程文档--(28)boot文件夹内容

boot文件夹内容 boot 文件夹内容bootcode.binstart*.elffixup*.datcmdline.txtconfig.txtissue.txtinitramfs*ssh 或 ssh.txt设备树blob文件 ( *.dtb )内核文件 ( *.img )overlays 文件夹 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 boot 文件…

SvelteKit 最新中文文档教程(20)—— 最佳实践之性能

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

【LangChain核心组件】Memory:让大语言模型拥有持续对话记忆的工程实践

目录 一、Memory架构设计解析 1. 核心组件关系图 2. 代码中的关键实现 二、对话记忆的工程实现 1. 消息结构化存储 2. 动态提示组装机制 三、Memory类型选型指南 四、生产环境优化实践 1. 记忆容量控制 2. 记忆分片策略 3. 记忆检索增强 五、典型问题调试技巧 1. …

适应 AI 时代的软件开发流程:用 AI + TDD 构建可维护项目

🧠 适应 AI 时代的软件开发流程:用 AI + TDD 构建可维护项目 本文面向有系统开发经验的工程师,分享如何结合 Git 管理、AI 协作、YAML 驱动与 TDD 开发方式,高效构建一个可维护、可协作、可交付的嵌入式或通用工程项目。适合 BLE 模块、协议栈组件、物联网控制系统等项目落…

使用 chromedriver 实现网络爬虫【手抄】

1、引用 selenium 包 <dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.29.0</version> </dependency> <dependency><groupId>org.seleniumhq.seleniu…