Springboot项目Druid运行时动态连接多数据源的功能
项目支持多数据库连接是个很常见的需求,这不仅是要在编译前连已经知道的多个数据库,有时还要在程序运行时连后期增加的多个数据源来获得数据。
一、编译前注册数据库连接
1.引入依赖包
<!-- springboot 3.x --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<!-- springboot 2.x --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId>
</dependency>
2.配置文件
一般本地应用可能有多个数据源,比如,需要支持读写分离的主从数据库配置,可能的application-druid.yml配置文件代码如下:
# 数据源配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverdynamic:primary: MASTERdatasource:# 主库数据源MASTER:url: jdbc:mysql://127.0.0.1/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456# 从库数据源SLAVE:url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456druid:# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置连接超时时间connectTimeout: 30000# 配置网络超时时间socketTimeout: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username: ruoyilogin-password: 123456filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
3.配置DruidConfig
/*** druid 配置多数据源* */
@Configuration
public class DruidConfig
{/** 主数据库配置 */@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}/** 从数据库配置 */@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DataSource slaveDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}/** 动态数据源 */@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource){Map<Object, Object> targetDataSources = new HashMap<>();// 加入主数据库配置targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);// 加入从数据库配置setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(masterDataSource, targetDataSources);}/*** 设置数据源* * @param targetDataSources 备选数据源集合* @param sourceName 数据源名称* @param beanName bean名称*/public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName){try{DataSource dataSource = SpringUtils.getBean(beanName);targetDataSources.put(sourceName, dataSource);}catch (Exception e){}}
}
4.配置DynamicDataSource
新建DynamicDataSource 类来继承AbstractRoutingDataSource 类。
继承自 Spring 提供的 AbstractRoutingDataSource,通过重写 determineCurrentLookupKey 方法,根据上下文信息动态选择当前使用的数据源。
/*** 动态数据源类,用于实现多数据源切换。*/
public class DynamicDataSource extends AbstractRoutingDataSource {/*** 构造函数,初始化默认数据源和目标数据源映射。** @param defaultTargetDataSource 默认数据源,在未指定其他数据源时使用* @param targetDataSourceMap 目标数据源映射,包含多个可选的数据源*/public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSourceMap) {// 设置默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);// 设置目标数据源映射super.setTargetDataSources(targetDataSourceMap);// 初始化父类属性super.afterPropertiesSet();}/*** 确定当前使用的数据源键。* 该方法会根据上下文中的数据源类型来决定使用哪个数据源。** @return 当前使用的数据源键*/@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceType();}}
5.配置DynamicDataSourceContextHolder
例如在web应用这种多线程的环境中,每个线程需要执行访问的数据库都不一样。因此需要给每个线程设置独立变量。
新建DynamicDataSourceContextHolder文件,代码如下:
/*** 数据源切换处理* */
public class DynamicDataSourceContextHolder
{public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/*** 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源的变量*/public static void setDataSourceType(String dsType){log.info("切换到{}数据源", dsType);CONTEXT_HOLDER.set(dsType);}/*** 获得数据源的变量*/public static String getDataSourceType(){return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void clearDataSourceType(){CONTEXT_HOLDER.remove();}
}
6.配置AOP切面类
通过 AOP 拦截带有 @DataSource 注解的方法或类,在方法执行前设置数据源,在方法执行后清除数据源,确保每个请求都能正确使用指定的数据源。
代码如下:
/*** 多数据源处理切面类。*/
@Aspect
@Order(1)
@Component
public class DataSourceAspect {protected Logger logger = LoggerFactory.getLogger(getClass());/*** 定义切入点,匹配带有 @DataSource 注解的方法或类。*/@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"+ "|| @within(com.ruoyi.common.annotation.DataSource)")public void dsPointCut() {}/*** 环绕通知,拦截 dsPointCut 切入点匹配的方法。* 在方法执行前设置数据源类型,在方法执行后清除数据源类型。** @param point 当前连接点对象* @return 方法返回值* @throws Throwable 如果方法执行过程中抛出异常*/@Around("dsPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {DataSource dataSource = getDataSource(point);if (StringUtils.isNotNull(dataSource)) {// 根据注解配置设置数据源类型if ("".equals(dataSource.name())) {DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());} else {DynamicDataSourceContextHolder.setDataSourceType(dataSource.name());}}try {// 执行目标方法return point.proceed();} finally {// 方法执行完毕后清除数据源类型DynamicDataSourceContextHolder.clearDataSourceType();}}/*** 获取当前方法或类上的 @DataSource 注解配置。** @param point 当前连接点对象* @return 数据源配置信息*/public DataSource getDataSource(ProceedingJoinPoint point) {MethodSignature signature = (MethodSignature) point.getSignature();// 从方法上查找 @DataSource 注解DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);if (Objects.nonNull(dataSource)) {return dataSource;}// 如果方法上没有找到,则从类上查找 @DataSource 注解return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);}
}
7.使用方式
现在可以通过注解选择要使用哪个数据库。
在需要使用多数据源方法或类上添加@DataSource注解,其中value用来表示数据源。
@DataSource(value = DataSourceType.SLAVE)
public List<SysUser> selectUserList(SysUser user)
{return userMapper.selectUserList(user);
}
@Service
@DataSource(value = DataSourceType.SLAVE)
public class SysUserServiceImpl{}
或者手动切换数据源
public List<SysUser> selectUserList(SysUser user)
{DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.SLAVE.name());List<SysUser> userList = userMapper.selectUserList(user);DynamicDataSourceContextHolder.clearDataSourceType();return userList;
}

二、运行时访问数据库
前面访问多数据源的方式必须提前在yaml这样的配置文件中提前填写好数据库的连接属性。
但是类似BI展示这样的软件项目可能得访问十几个业务的数据源,并且别的数据源的访问信息还时刻在变。这样的话,就不方便把数据库的连接属性提前写在配置文件中了。
1.配置数据管理工具
@Configuration
public class DataSourceManagement implements InitializingBean {protected final Logger logger = LoggerFactory.getLogger(DataSourceManagement.class);/*** 额外数据源*/private Map<String, DataSource> targetDataSources = new HashMap<>();/*** 配置文件的数据源*/@Autowiredprivate DynamicDataSourceProperties dataSourceProperties;@Autowiredprivate CreateDataSource c;@Autowired(required = false)private AfterCreateDataSource afterCreateDataSource;private DynamicDataSource dynamicDataSource;/*** 创建并返回动态数据源实例。** @return 动态数据源实例*/@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource() {Map<Object, Object> targetDataSourceMap = new HashMap<>(targetDataSources);this.dynamicDataSource = new DynamicDataSource(targetDataSources.get(dataSourceProperties.getPrimary()), targetDataSourceMap);return this.dynamicDataSource;}/*** 验证数据源是否可用。** @param dataSource 要验证的数据源*/public void validateDataSource(DataSource dataSource) {try (Connection conn = dataSource.getConnection()) {String validationQuery = "SELECT 1";try (Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(validationQuery)) {if (!(rs.next() && rs.getInt(1) == 1)) {throw new RuntimeException("数据源连接验证失败:查询结果不正确");}}} catch (SQLException e) {throw new RuntimeException("数据源连接验证失败", e);}}/*** 在所有依赖项设置完成后执行此方法。* 初始化所有配置的数据源,并进行连接验证。*/@Overridepublic void afterPropertiesSet() throws Exception {dataSourceProperties.getDatasource().forEach((name, props) -> {Properties properties = dataSourceProperties.build(props);CommonDataSource commonDataSource = c.createDataSource(name, properties);if (afterCreateDataSource != null) {afterCreateDataSource.afterCreateDataSource(name, properties, commonDataSource);}DataSource dataSource = (DataSource) commonDataSource;logger.info("数据源:{} 校验中.......", name);// 计时long start = System.currentTimeMillis();validateDataSource(dataSource);logger.info("数据源:{} 链接成功,耗时:{}ms", name, System.currentTimeMillis() - start);this.putDataSource(name, dataSource);});}/*** 添加或更新一个数据源,并创建相应的SqlSessionFactory。** @param name 数据源名称* @param dataSource 数据源实例*/public void putDataSource(String name, DataSource dataSource) {targetDataSources.put(name, dataSource);}/*** 添加一个新的数据源。** @param name 数据源名称* @param properties 数据源属性*/public void addDataSourceWithCheck(String name, Properties properties) {if (targetDataSources.containsKey(name)) {logger.info("数据源" + name + "之前已经创建,准备测试数据源是否正常...");//throw new RuntimeException("数据源已存在");} else {CommonDataSource commonDataSource = c.createDataSource(name, properties);if (afterCreateDataSource != null) {afterCreateDataSource.afterCreateDataSource(name, properties, commonDataSource);}DataSource dataSource = (DataSource) commonDataSource;logger.info("数据源:{} 校验中.......", name);// 计时long start = System.currentTimeMillis();validateDataSource(dataSource);logger.info("数据源:{} 链接成功,耗时:{}ms", name, System.currentTimeMillis() - start);this.putDataSource(name, dataSource);HashMap<Object, Object> objectHashMap = new HashMap<>(this.targetDataSources);// 将map赋值给父类的TargetDataSourcesthis.dynamicDataSource.setTargetDataSources(objectHashMap);// 重要:将TargetDataSources中的连接信息放入resolvedDataSources管理,否则无法切换数据源this.dynamicDataSource.afterPropertiesSet();logger.debug("添加数据源成功,名称:{}", name);}}}
2.创建数据源
通过 DruidXADataSource 创建数据源,并使用 DruidConfig 和 DynamicDataSourceProperties 配置数据源属性。
/*** 数据源创建类,实现 CreateDataSource 接口。* */
@Component
public class DataSourceCreate implements CreateDataSource {@Autowiredprivate DynamicDataSourceProperties properties;@Autowiredprivate DruidConfig druidConfig;/*** 创建数据源的方法。** @param name 数据源名称* @param prop 数据源配置属性* @return 创建的数据源对象*/@Overridepublic DataSource createDataSource(String name, Properties prop) {// 创建 DruidXADataSource 实例DruidXADataSource dataSource = new DruidXADataSource();// 将创建的数据源添加到 DruidConfig 的数据源列表中druidConfig.getDruidDataSources().add(dataSource);// 设置数据源的连接属性dataSource.setConnectProperties(prop);// 使用 DynamicDataSourceProperties 配置数据源的其他属性properties.setProperties(dataSource, prop);// 返回创建的数据源对象return dataSource;}
}
3.准备实体
准备个存储数据库连接属性的实体,用于接收信息。
@Data
public class DataSource {private String id;private String connIp;private String connPort;private String connDbName;private String connUserName;private String connPassWord;private String connName;private String connType;private String connProperty;private String connDriverClass;
}
4.调用方式
写一个服务类,将从某个存储数据库连接信息的表里查出所有数据源。然后根据连接属性创建动态数据源。
@Service
public class DBChangeServiceImpl implements IDBChangeService {private final Logger logger = LoggerFactory.getLogger(DBChangeServiceImpl.class);@AutowiredDataSourceMapper dataSourceMapper;@Autowiredprivate DataSourceManagement dataSourceManagement;/*** 获取数据源* @return*/@Overridepublic List<DataSource> get() {return dataSourceMapper.get();}/*** 切换数据源* @param datasourceId* @return*/@Overridepublic boolean changeDb(String datasourceId) {//清除本线程的数据源DynamicDataSourceContextHolder.clearDataSourceType();logger.debug("清除本线程的数据源");//获取所有数据源List<DataSource> dataSourcesList = dataSourceMapper.get();logger.debug("获取到的数据源列表: {}", JSON.toJSONString(dataSourcesList));//遍历所有数据源,切换到指定数据源for (DataSource dataSource : dataSourcesList) {if (dataSource.getId().equals(datasourceId)) {logger.info(JSON.toJSONString(dataSource));logger.info("需要使用的的数据源已经找到,datasourceId是:" + dataSource.getId());Properties properties = buildDataSourceProperties(dataSource);//创建数据源连接&检查 若存在则不需重新创建try {// 使用DataSourceManagement来创建数据源并检查dataSourceManagement.addDataSourceWithCheck(dataSource.getId(), properties);// 切换数据源DynamicDataSourceContextHolder.setDataSourceType(dataSource.getId());logger.info("标记切换到数据源:"+datasourceId);return true;} catch (Exception e) {logger.error("数据源切换失败", e);e.printStackTrace();}}}logger.debug("未找到目标数据源");return false;}private Properties buildDataSourceProperties(DataSource dataSource) {Properties properties = new Properties();properties.setProperty("url", "jdbc:mysql://" + dataSource.getConnIp() + ":" + dataSource.getConnPort() + "/" + dataSource.getConnDbName());properties.setProperty("username", dataSource.getConnUserName());properties.setProperty("password", dataSource.getConnPassWord());properties.setProperty("driverClassName", dataSource.getConnDriverClass());// 添加其他必要的属性return properties;}}
切换数据源执行sql语句后,记得把数据源再切回去。
public AjaxResult runWithSql(String datasourceid, String sql){//切换到数据库dbChangeService.changeDb(datasourceid);System.out.println("Current DataSource Type: " + DynamicDataSourceContextHolder.getDataSourceType());System.out.println("RunWithSql: "+sql);List<Map<String, Object>> maps = execSqlService.runWithSql(sql);System.out.println("=======>"+JSON.toJSONString(maps));//切回主数据源DynamicDataSourceContextHolder.clearDataSourceType();return AjaxResult.success(maps);}
可以自行测试,发现连接成功了。

相关文章:
Springboot项目Druid运行时动态连接多数据源的功能
项目支持多数据库连接是个很常见的需求,这不仅是要在编译前连已经知道的多个数据库,有时还要在程序运行时连后期增加的多个数据源来获得数据。 一、编译前注册数据库连接 1.引入依赖包 <!-- springboot 3.x --><dependency><groupId&g…...
字符串匹配——KMP算法
前言 刷到字符串匹配的力扣题了【28. 实现 strStr() 】,这题简单吧用库函数做就可以,说难吧,就得引出大名鼎鼎的线性匹配算法——KMP。 目录 KMP 算法背景与原理算法优势 前缀表1. 构建Next数组2. 搜索匹配 KMP 算法背景与原理 KMP&#x…...
Qt开发技术【下拉复选框 MultiSelectComboBox 自定义全选项】
继承ComboBox完成下拉复选框 自定义全选项 效果图 整个控件继承于QCombobox类。主要修改QLineEdit、QListWidget这两部分,QComboBox提供如下接口,可以将这两部分设置为新建的QLineEdit、QListWidget对象 CMultiSelectComboBox::CMultiSelectComboBo…...
20_HTML5 SSE --[HTML5 API 学习之旅]
HTML5 Server-Sent Events (SSE) 是一种技术,它允许服务器向浏览器推送更新。与传统的轮询不同,SSE提供了真正的单向实时通信通道:服务器可以主动发送数据到客户端,而不需要客户端发起请求。这对于实现实时更新的应用非常有用&…...
jetson Orin nx + yolov8 TensorRT 加速量化 环境配置
参考【Jetson】Jetson Orin NX纯系统配置环境-CSDN博客 一 系统环境配置: 1.更换源: sudo vi /etc/apt/sources.list.d/nvidia-l4t-apt-source.list2.更新源: sudo apt upgradesudo apt updatesudo apt dist-upgrade sudo apt-get updat…...
Android Studio IDE环境配置
需要安装哪些东西: Java jdk Java Downloads | OracleAndroid Studio 下载 Android Studio 和应用工具 - Android 开发者 | Android DevelopersAndroid Sdk 现在的Android Studio版本安装时会自动安装,需要注意下安装的路径Android Studio插件…...
PTA 7-2 0/1背包问题(回溯法) 作者 王东 单位 贵州师范学院
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求重量和恰好为W具有最大的价值。 输入格式: 第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。 输出格式: 第一行输出装入背包内…...
Matlab环形柱状图
数据准备: 名称 数值 Aa 21 Bb 23 Cc 35 Dd 47 保存为Excel文件后: % Load data from Excel file filename data.xlsx; % Ensure the file is in the current folder or provide full path dataTable readtable(filena…...
【AI大模型】探索GPT模型的奥秘:引领自然语言处理的新纪元
目录 🍔 GPT介绍 🍔 GPT的架构 🍔 GPT训练过程 3.1 无监督的预训练语言模型 3.2 有监督的下游任务fine-tunning 🍔 小结 学习目标 了解什么是GPT.掌握GPT的架构.掌握GPT的预训练任务. 🍔 GPT介绍 GPT是OpenAI公…...
5.Python爬虫相关
爬虫 爬虫原理 爬虫,又称网络爬虫,是一种自动获取网页内容的程序。它模拟人类浏览网页的行为,发送HTTP请求,获取网页源代码,再通过解析、提取等技术手段,获取所需数据。 HTTP请求与响应过程 爬虫首先向…...
Windows系统上配置eNSP环境的详细步骤
华为eNSP(Enterprise Network Simulation Platform)是一款针对华为数通网络设备的网络仿真平台,用于辅助工程师进行网络技术学习、方案验证和故障排查等工作。以下是在Windows系统上配置eNSP环境的详细步骤: 1. 准备工作 下载安…...
Database.NET——一款轻量级多数据库客户端工具
文章目录 Database.NET简介下载使用使用场景总结 Database.NET简介 Database.NET 是一个功能强大且易于使用的数据库管理工具,适用于多种数据库系统。它为开发者和数据库管理员提供了一个统一的界面,可以方便地管理和操作不同类型的数据库。 支持的数据…...
新浪微博C++面试题及参考答案
多态是什么?请详细解释其实现原理,例如通过虚函数表实现。 多态是面向对象编程中的一个重要概念,它允许不同的对象对同一消息或函数调用做出不同的响应,使得程序具有更好的可扩展性和灵活性。 在 C 中,多态主要通过虚函…...
计算机视觉目标检测-1
文章目录 摘要Abstract1.目标检测任务描述1.1 目标检测分类算法1.2 目标定位的简单实现思路1.2.1 回归位置 2.R-CNN2.1 目标检测-Overfeat模型2.1.1 滑动窗口 2.2 目标检测-RCNN模型2.2.1 非极大抑制(NMS) 2.3 目标检测评价指标 3.SPPNet3.1 spatial pyr…...
【物联网技术与应用】实验15:电位器传感器实验
实验15 电位器传感器实验 【实验介绍】 电位器可以帮助控制Arduino板上的LED闪烁的时间间隔。 【实验组件】 ● Arduino Uno主板* 1 ● 电位器模块* 1 ● USB电缆*1 ● 面包板* 1 ● 9V方型电池* 1 ● 跳线若干 【实验原理】 模拟电位器是模拟电子元件,模…...
java常用类(上)
笔上得来终觉浅,绝知此事要躬行 🔥 个人主页:星云爱编程 🔥 所属专栏:javase 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 一、包装类 1.1包装类…...
包管理工具npm、yarn、pnpm、cnpm详解
1. 包管理工具 1.1 npm # 安装 $ node 自带 npm# 基本用法 npm install package # 安装包 npm install # 安装所有依赖 npm install -g package # 全局安装 npm uninstall package # 卸载包 npm update package # 更新包 npm run script #…...
CI/CD是什么?
CI/CD 定义 CI/CD 代表持续集成和持续部署(或持续交付)。它是一套实践和工具,旨在通过自动化构建、测试和部署来改进软件开发流程,使您能够更快、更可靠地交付代码更改。 持续集成 (CI):在共享存储库中自动构建、测试…...
[Java]合理封装第三方工具包(附视频)
-1.视频链接 视频版: 视频版会对本文章内容进行详细解释 [Java]合理封装第三方工具包_哔哩哔哩_bilibili 0.核心思想 对第三方工具方法进行封装,使其本地化,降低记忆和使用成本 1.背景 在我们的项目中,通常会引用一些第三方工具包,或者是使用jdk自带的一些工具类 例如: c…...
常规配置、整合IDEA
目录 Redis常规配置 tcp-keepalive security Jedis RedisTemplate 连接池技术 Lua脚本 Jedis集群 Redis应用问题&解决方案 缓存穿透 缓存击穿 缓存雪崩 分布式锁 Redis实现分布式锁 Redis新功能 ACL Redis常规配置 tcp-keepalive security redis.conf中…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
