Springboot 配置 doris 连接

一. 使用 druid 连接池

因为 Doris 的前端(FE)兼容了 MySQL 协议,可以像连 MySQL 一样连 Doris。这是 Doris 的一个核心设计特性,目的是方便接入、简化生态兼容。

首先需要引入 pom 依赖:
        <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.20</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.1</version></dependency>

在springboot 的yml文件中配置:

spring:datasource:url: jdbc:mysql://192.168.1.111:9030/database_test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=3username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 20 # 初始化时预创建的连接数min-idle: 20  #最低 保持空闲的连接数max-active: 200 # 最大连接池数量max-wait: 30000 # 连接池最大允许等待的时间(单位:毫秒)validation-query: SELECT 1 # 验证连接是否有效test-while-idle: true # 在连接池空闲时是否验证连接的有效性test-on-borrow: true # 在从连接池中借用连接时是否验证连接的有效性test-on-return: false # 在连接被归还到连接池时是否验证连接的有效性time-between-eviction-runs-millis: 30000 # 空闲连接回收的频率(多久进行一次检查),单位为毫秒min-evictable-idle-time-millis: 300000 # 空闲超过多长时间后在下次检查时会被回收,单位为毫秒max-evictable-idle-time-millis: 600000 # 最大空闲时间的上限, 超过被强制回收keep-alive: true # 主动保活连接,避免网络层断链phy-timeout-millis: 1800000   # 物理连接的 最大空闲时间,单位是毫秒。remove-abandoned: true # 指定时间内没有被正常释放(例如没有及时关闭),连接池会主动回收这个连接。remove-abandoned-timeout: 300 # 连接被视为废弃的超时时间,单位为秒。

二.多数据源配置 doris 连接

有的时候我们需要连接多数据源, 比如要同时连接 mysql 和 doris, 这时候我们就要进行一些额外的配置。

1.配置文件配置

spring:datasource:mysql: # mysql 配置url: jdbc:mysql://192.168.1.111:3306/mysql_database_test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=trueusername: rootpassword: 654321driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:validation-query: SELECT 1max-active: 10min-idle: 2initial-size: 2doris: # doris配置url: jdbc:mysql://192.168.1.111:9030/database_test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=3username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 20 # 初始化时预创建的连接数min-idle: 20  #最低 保持空闲的连接数max-active: 200 # 最大连接池数量max-wait: 30000 # 连接池最大允许等待的时间(单位:毫秒)validation-query: SELECT 1 # 验证连接是否有效test-while-idle: true # 在连接池空闲时是否验证连接的有效性test-on-borrow: true # 在从连接池中借用连接时是否验证连接的有效性test-on-return: false # 在连接被归还到连接池时是否验证连接的有效性time-between-eviction-runs-millis: 30000 # 空闲连接回收的频率(多久进行一次检查),单位为毫秒min-evictable-idle-time-millis: 300000 # 空闲超过多长时间后在下次检查时会被回收,单位为毫秒max-evictable-idle-time-millis: 600000 # 最大空闲时间的上限, 超过被强制回收keep-alive: true # 主动保活连接,避免网络层断链phy-timeout-millis: 1800000   # 物理连接的 最大空闲时间,单位是毫秒。remove-abandoned: true # 指定时间内没有被正常释放(例如没有及时关闭),连接池会主动回收这个连接。remove-abandoned-timeout: 300 # 连接被视为废弃的超时时间,单位为秒。

spring.datasource下的 mysql 和 doris可以自己自定义, 因为不管用什么名字, 我们能需在java中进行数据库数据源配置。

2.doris 数据库数据源配置:

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/*** doris 数据库数据源配置* 指定要扫描的 Mapper 接口包路径(Doris用)* 指定对应的 SqlSessionFactory Bean 名称* @author HY* @date 2025-06-23*/
@Configuration
@MapperScan(basePackages  = "com.ashen.test.mapper.doris" , sqlSessionFactoryRef = "dorisSqlSessionFactory")
public class DorisConfig {/*** mybatis xml 文件位置*/private static final String MYBATIS_LOCATION = "classpath*:mybatis/doris/*.xml";/*** 实体类文件位置*/private static final String TYPE_ALIASES_PACKAGE = "com.ashen.test.common.model.entity.doris.*";/*** 创建 Doris 数据源 Bean,注入名称为 "dorisDataSource"* @return*/@Bean("dorisDataSource")@ConfigurationProperties(prefix = "spring.datasource.doris")public DataSource getDb1DataSource(){// 构建数据源对象(默认用的是 HikariDataSource, 这个需要注意)//        return DataSourceBuilder.create().build();return new com.alibaba.druid.pool.DruidDataSource();}/*** 创建 SqlSessionFactory Bean,供 MyBatis 使用,注入名为 "dorisSqlSessionFactory"* @param dataSource 注入上面定义的 Doris 数据源* @return* @throws Exception*/@Bean("dorisSqlSessionFactory")public SqlSessionFactory dorisSqlSessionFactory(@Qualifier("dorisDataSource") DataSource dataSource) throws Exception {// 创建工厂 BeanSqlSessionFactoryBean bean = new SqlSessionFactoryBean();// 设置数据源bean.setDataSource(dataSource);// 加载 Mybatis XML 文件bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MYBATIS_LOCATION));// 设置实体类包路径,用于简化 XML 中类型的全路径书写bean.setTypeAliasesPackage(TYPE_ALIASES_PACKAGE);// 获取 SqlSessionFactory 实例return bean.getObject();}/*** 创建 SqlSessionTemplate Bean(线程安全的 SqlSession 封装)* 用于执行 SQL、提交/回滚事务等* @param sqlSessionFactory* @return*/@Bean("dorisSqlSessionTemplate")public SqlSessionTemplate dorisSqlSessionTemplate(@Qualifier("dorisSqlSessionFactory") SqlSessionFactory sqlSessionFactory){// 创建并返回模板实例return new SqlSessionTemplate(sqlSessionFactory);}}

3.msyql 数据库数据源配置:

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/*** mysql 数据库数据源配置* 指定要扫描的 Mapper 接口包路径(Mysql 用)* 指定对应的 SqlSessionFactory Bean 名称* @author HY* @date 2025-06-23*/
@Configuration
@MapperScan(basePackages = "com.ashen.test.mapper.mysql", sqlSessionFactoryRef = "mysqlSqlSessionFactory")
public class MysqlConfig {/*** mybatis xml 文件位置*/private static final String MYBATIS_LOCATION = "classpath*:mybatis/mysql/*.xml";/*** 实体类文件位置*/private static final String TYPE_ALIASES_PACKAGE = "com.ashen.test.common.model.entity.mysql.*";/*** 创建 MySQL 数据源对象* 被 @Primary 标记为主数据源,默认注入优先使用这个* 从 application.yml 读取以 spring.datasource.mysql 为前缀的属性进行绑定*/@Primary@Bean(name="mysqlDataSource")@ConfigurationProperties(prefix = "spring.datasource.mysql")public DataSource mysqlDataSource() {// 使用 DataSourceBuilder 构建数据源,支持 HikariCP、Druid 等(取决于依赖)
//        return DataSourceBuilder.create().build();return new com.alibaba.druid.pool.DruidDataSource();}/*** 创建 MySQL 对应的 SqlSessionFactory,供 MyBatis 使用* 指定数据源、Mapper XML 文件路径、实体别名路径* @param dataSource 注入 mysqlDataSource*/@Primary@Bean("mysqlSqlSessionFactory")public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {// 创建 SqlSessionFactoryBean(MyBatis 与 Spring 整合的桥梁)SqlSessionFactoryBean bean = new SqlSessionFactoryBean();// 设置数据源bean.setDataSource(dataSource);// 指定 MyBatis 的 mapper XML 文件路径(如果不配会找不到 SQL 映射)bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MYBATIS_LOCATION));// 设置实体类所在包,用于自动生成别名bean.setTypeAliasesPackage(TYPE_ALIASES_PACKAGE);// 返回 SqlSessionFactory 实例return bean.getObject();}/*** 创建 MyBatis 的 SqlSessionTemplate(线程安全、Spring 管理的 SqlSession)* 用于执行 SQL 操作、事务管理等* @param sqlSessionFactory 注入上一步创建的 SqlSessionFactory*/@Primary@Bean("mysqlSqlSessionTemplate")public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory){// 用工厂创建出模板return new SqlSessionTemplate(sqlSessionFactory);}
}

注: 这里有个坑, 就是在 mysqlDataSource() 方法中, 必须显示的返回 。

return new com.alibaba.druid.pool.DruidDataSource();

如果采用:

return DataSourceBuilder.create().build();

最终将默认采用 Spring Boot 内建的 Hikari 数据源模块。

三.druid 状态监控

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class DruidMonitor {@Lazy@Autowiredprivate DruidDataSource dataSource;// 每1分钟输出一次连接池的状态@Scheduled(fixedRate = 600000)public void printDruidStats() {System.out.println("活跃连接数 : " + dataSource.getActiveCount());System.out.println("空闲连接数 : " + dataSource.getPoolingCount());System.out.println("最大允许的活跃连接数 : " + dataSource.getMaxActive());System.out.println("连接池中获取连接的最大等待时间 : " + dataSource.getMaxWait());System.out.println("连接池创建过的连接总数 : " + dataSource.getCreateCount());System.out.println("已经关闭的连接总数 : " + dataSource.getCloseCount());System.out.println("===================================");}
}

四. 连接超时问题

空闲连接超时后, 会被连接池回收, 当再次使用该连接的时候, 会报连接已关闭的错误, 这种情况并不常见, 但是有时候又会突然出现, 让我们以为是配置上有问题。

例如:

当我们遇到需要从socket或者消息队列中持续取数据时, 经常会在 while(true) 中接收消息并插入数据库, 如果我们将 @Transactional 放在 while(true) 之上的方法上, 那么整个事务周期内都将使用同一个 durid 连接, 如果长时间未从远程消息队列或者socket中获取到数据, 那么该连接就会被回收, 当再次来到数据并写库时, 就会报连接已关闭的错误。

    @Transactional(readOnly = false, rollbackFor = Exception.class)public void insert() {....while(true){testMapper.insert(param);}}

因此要注意: 不要将 @Transactional 加到需要长时间运行的方法之上。

而是将插入方法脱离出去, 如下:

    public void insert() {....while(true){testMapper.insertData(param);}}@Transactional(readOnly = false, rollbackFor = Exception.class)public void insertData() {testMapper.insert(param);}

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

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

相关文章

Linux 系统启动与 GRUB2 核心操作指南

Linux 系统启动与 GRUB2 核心操作指南 Linux 系统的启动过程是一个环环相扣的链条&#xff0c;从硬件自检到用户登录&#xff0c;每一步都依赖关键组件的协作。其中&#xff0c;GRUB2 引导器和systemd 进程是核心枢纽&#xff0c;而运行级别则决定了系统的启动状态。以下是系统…

供应链分销代发源码:一站式打通供应商供货、平台定价、经销商批发及零售环节

在当前复杂的市场环境中&#xff0c;供应链管理成为企业发展的关键。尤其对于电商平台来说&#xff0c;高效、精准的供应链管理不仅能提升运营效率&#xff0c;还能增强市场竞争力。为了应对日益复杂的供应链挑战&#xff0c;核货宝供应链分销代发系统应运而生&#xff0c;旨在…

机器学习、深度学习与数据挖掘:核心技术差异、应用场景与工程实践指南

技术原理与核心概念数据挖掘作为知识发现的关键技术&#xff0c;其核心在于通过算法自动探索数据中的潜在模式。关联规则挖掘可以发现项目之间的有趣关联&#xff0c;如经典的"啤酒与尿布"案例&#xff1b;聚类分析能够将相似对象自动分组&#xff0c;常用于客户细分…

《C++初阶之STL》【stack/queue/priority_queue容器适配器:详解 + 实现】(附加:deque容器介绍)

【stack/queue/priority_queue容器适配器&#xff1a;详解 实现】目录前言&#xff1a;------------标准接口介绍------------一、栈&#xff1a;stack标准模板库中的stack容器适配器是什么样的呢&#xff1f;1. 栈的基本操作std::stack::topstd::stack::pushstd::stack::pop2…

Thymeleaf 模板引擎原理

Thymeleaf 的模板文件&#xff0c;本质上是标准的 HTML 文件&#xff0c;只是“加了标记&#xff08; th&#xff1a;&#xff09;的属性”&#xff0c;让模板引擎在服务端渲染时能 识别并处理 这些属性&#xff0c;从而完成数据&#xff08;model&#xff09; 的填充。<!DO…

5、生产Redis高并发分布式锁实战

一、核心问题与解决方案 问题本质 #mermaid-svg-W1SnVWZe1AotTtDy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-W1SnVWZe1AotTtDy .error-icon{fill:#552222;}#mermaid-svg-W1SnVWZe1AotTtDy .error-text{fill:#5…

CS231n-2017 Lecture8深度学习框架笔记

深度学习硬件&#xff1a;CPU:CPU有数个核心&#xff0c;每个核心可以独立工作&#xff0c;同时进行多个线程&#xff0c;内存与系统共享GPU&#xff1a;GPU有上千个核心&#xff0c;但每个核心运行速度很慢&#xff0c;适合并行做类似的工作&#xff0c;不能独立工作&#xff…

以ros的docker镜像为例,探讨docker镜像的使用

标题以ros的docker镜像为例&#xff0c;探讨docker镜像的使用&#xff08;待完善&#xff09; 1. docker介绍&#xff08;以ros工程距离&#xff09; &#xff08;1&#xff09;个人理解&#xff1a;docker就是一个容器&#xff0c;主要的作用就是将环境打包好&#xff0c;方…

Android Audio实战——TimeCheck机制解析(十三)

上一篇文章我们虽然通过 tombstoned Log 推断出 audioserver 崩溃的原因就是系统调用内核接口时发生阻塞,导致 TimeCheck 检测超时异常而崩溃,但并没有实质性的证据证明是 kernel 层出现问题导致的崩溃,因此这里我们继续看一下 TimeCheck 的检测原理。 一、TimeCheck机制 T…

飞机大战小游戏

1.视觉设计&#xff1a;采用柔和的蓝紫色渐变背景&#xff0c;营造梦幻感飞机、敌机和子弹使用柔和的糖果色调添加了粒子爆炸效果&#xff0c;增强视觉反馈星星收集物增加游戏趣味性2.游戏机制&#xff1a;玩家使用左右方向键控制飞机移动空格键发射子弹P键暂停游戏击落敌机获得…

Linux 启动服务脚本

1. 创建命令文件# 创建可执行文件 touch 文件名称 例&#xff1a; touch stopServer.sh2. 命令文件授权# 授权文件可执行权限 chmod 777 文件名称 例&#xff1a; chmod 777 stopServer.sh3. 停止服务命令编写#!/bin/bash# 获取进程号 pidps -ef | grep -- /mnt/apache-tomcat-…

【华为机试】34. 在排序数组中查找元素的第一个和最后一个位置

文章目录34. 在排序数组中查找元素的第一个和最后一个位置描述示例 1&#xff1a;示例 2&#xff1a;示例 3&#xff1a;提示&#xff1a;解题思路算法分析问题本质分析双重二分查找详解左边界查找过程右边界查找过程算法流程图边界情况分析各种解法对比二分查找变种详解时间复…

【网络编程】WebSocket 实现简易Web多人聊天室

一、实现思路 Web端就是使用html JavaScript来实现页面&#xff0c;通过WebSocket长连接和服务器保持通讯&#xff0c;协议的payload使用JSON格式封装 服务端使用C配合第三方库WebSocket和nlonlohmann库来实现 二、Web端 2.1 界面显示 首先&#xff0c;使用html来设计一个…

AI 驱动、设施扩展、验证器强化、上线 EVM 测试网,Injective 近期动态全更新!

作为一个专注于金融应用、且具有高度可互操作性的高性能 Layer-1 区块链&#xff0c;Injective 自诞生以来便为开发者提供有即插即用的技术模块&#xff0c;以便开发者能够更好地搭建新一代 Web3 金融类应用。谈及项目发展的愿景和基本定位&#xff0c;创始团队曾提到希望 Inje…

Qt-----初识

1. 什么是Qt定义&#xff1a;Qt是一个跨平台的应用程序和用户界面框架&#xff0c;主要用于开发具有图形用户界面的应用程序&#xff0c;同时也支持非GUI程序的开发。 编程语言&#xff1a;主要使用C&#xff0c;但也提供了对Python&#xff08;PyQt&#xff09;、JavaScript&a…

理解微信体系中的 AppID、OpenID 和 UnionID

前言: 在开发微信相关的服务(如小程序,公众号,微信开放平台等)时,很多人都会接触到几个看起来相似但实际用途不同的额ID: AppiD, OpenID,UnionID. 搞清楚这三者的区别,是微信生态开发中的基本功,本文将从开发者视角触发,深入浅出地解释它们的关系,区别以及实际应用场景一.什么是…

FFmpeg,如何插入SEI自定义数据

FFmpeg&#xff0c;如何插入SEI自定义数据 一、什么是SEI&#xff1f; SEI&#xff08;Supplemental Enhancement Information&#xff0c;补充增强信息&#xff09;是H.264/H.265视频编码标准中的一种元数据载体&#xff0c;它允许在视频流中嵌入额外的信息&#xff0c;如时…

为什么分类任务偏爱交叉熵?MSE 为何折戟?

在机器学习的世界里&#xff0c;损失函数是模型的“指南针”——它定义了模型“好坏”的标准&#xff0c;直接决定了参数优化的方向。对于分类任务&#xff08;比如判断一张图片是猫还是狗&#xff09;&#xff0c;我们通常会选择交叉熵作为损失函数&#xff1b;而在回归任务&a…

[echarts]横向柱状图

前言 接到一个需求&#xff0c;需要展示一个横向的柱状图&#xff0c;按数量从大到小排序&#xff0c;并定时刷新 使用react配合echarts进行实现。 react引入echarts import React, { useEffect, useRef } from react; import * as echarts from echarts; import DeviceApi fro…

【开源项目】轻量加速利器 HubProxy 自建 Docker、GitHub 下载加速服务

​​引言​​ 如果你经常被 Docker 镜像拉取、GitHub 文件下载的龟速折磨&#xff0c;又不想依赖第三方加速服务&#xff08;担心稳定性或隐私&#xff09;&#xff0c;今天分享的 ​​HubProxy​​ 可能正是你需要的。这个开源工具用一行命令就能部署&#xff0c;以极低资源消…