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=3 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: 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=true username: root password: 654321 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: validation-query: SELECT 1 max-active: 10 min-idle: 2 initial-size: 2 doris: # 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=3 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: 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 { // 创建工厂 Bean SqlSessionFactoryBean 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 @Autowired private 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); }
到此这篇关于Springboot配置doris连接的文章就介绍到这了,更多相关Springboot doris连接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!