2026/6/20 3:47:31
网站建设
项目流程
织梦汽车网站模板免费下载,重庆做网站重庆做网站,wordpress memcache插件,县网站建设检查情况汇报熟悉 Spring Boot 3 的开发者#xff0c;都知道它在简化开发流程、提高开发效率方面的出色表现吧#xff01;但是#xff0c;在实际业务场景中#xff0c;大家肯定都碰到过这样的棘手问题#xff1a;订单数据存放在 MySQL 里#xff0c;库存数据在 PostgreSQL 中#xf…熟悉 Spring Boot 3 的开发者都知道它在简化开发流程、提高开发效率方面的出色表现吧但是在实际业务场景中大家肯定都碰到过这样的棘手问题订单数据存放在 MySQL 里库存数据在 PostgreSQL 中用户数据又保存在 MongoDB 中当多种数据源同时存在时想要实现统一查询简直比登天还难。所以呢今天我就亮出我的“终极大招”——Apache Calcite着重给大家讲讲它怎样与 Spring Boot 3 实现无缝集成还会分享一些可以直接拿来使用的经典应用场景。掌握了这一招多数据源查询的难题就能轻松解决啦一、核心认知Apache Calcite 为何是多数据源查询的利器在动手集成前咱们先把核心逻辑搞明白为啥 Calcite 能成为多数据源查询的“万能钥匙”它的核心优势到底在哪1.1 不止是查询引擎Calcite 的核心定位Apache Calcite 本质是一个动态数据管理框架而非传统的数据库。它最核心的价值在于“解耦”——将数据存储与数据查询分离无论数据存在哪里、是什么格式都能通过统一的 SQL 接口进行查询。说通俗点Calcite 就像个“超级数据翻译官”——不管数据藏在哪个数据源里、是什么格式你只要写一套标准 SQL它就能翻译成对应数据源能懂的指令最后把结果整理成统一格式返回。这也是它能搞定多数据源查询的核心秘诀1.2 Calcite 的核心能力拆解统一 SQL 接口支持标准 SQL无论底层是关系型数据库MySQL、PostgreSQL、非关系型数据库MongoDB、Redis还是文件CSV、Parquet、大数据引擎Hive、Spark都能通过同一套 SQL 查询。强大的查询优化内置基于规则和成本的查询优化器能自动优化 SQL 执行计划提升查询效率尤其是在复杂多表关联、跨数据源查询场景下优化效果明显。灵活的数据源适配通过“适配器Adapter”机制适配不同数据源社区已提供大量现成适配器也支持自定义开发适配特殊数据源。轻量级集成核心依赖体积小无复杂依赖可轻松集成到 Spring Boot、Spring Cloud 等主流 Java 开发框架中无需单独部署独立服务也支持独立部署。二、重点实战Spring Boot 3 集成 Calcite 核心步骤既然大家都熟悉 Spring Boot 3 的基础操作我就不啰嗦项目搭建这些常规步骤了直接聚焦 Calcite 集成的核心环节每一步都附完整代码和避坑提醒跟着做就能成2.1 核心依赖引入第一步先引依赖在 pom.xml 里加好 Calcite 核心包、对应数据源的适配器再配上 MyBatis Plus 的核心依赖替换掉原来的 Jdbc 依赖就行具体如下!-- Calcite 核心依赖 -- dependency groupIdorg.apache.calcite/groupId artifactIdcalcite-core/artifactId version1.36.0/version /dependency !-- MySQL 适配器用于适配 MySQL 数据源 -- dependency groupIdorg.apache.calcite/groupId artifactIdcalcite-mysql/artifactId version1.36.0/version /dependency !-- MongoDB 适配器用于适配 MongoDB 数据源 -- dependency groupIdorg.apache.calcite/groupId artifactIdcalcite-mongodb/artifactId version1.36.0/version /dependency !-- Spring Boot 与 MyBatis Plus 集成核心依赖 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version !-- 适配 Spring Boot 3 的稳定版 -- /dependency !-- 数据库连接池依赖MyBatis Plus 需连接池支持 -- dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.20/version /dependency这里有 3 个避坑点必须强调下Calcite 所有组件版本要统一不然容易出现类加载异常MyBatis Plus 得选适配 Spring Boot 3 的版本3.5.3一定要加连接池依赖不然 Calcite 数据源没法被 MyBatis Plus 正常管理。2.2 核心配置Calcite 模型文件编写模型文件是 Calcite 识别数据源的关键一般用 JSON 格式放在 resources 目录下命名为 calcite-model.json 就行。下面给大家一个适配 MySQL 和 MongoDB 双数据源的示例直接改改连接信息就能用{ version: 1.0, defaultSchema: ecommerce, schemas: [ { name: ecommerce, type: custom, factory: org.apache.calcite.adapter.jdbc.JdbcSchema$Factory, operand: { jdbcUrl: jdbc:mysql://localhost:3306/ecommerce_order?useSSLfalseserverTimezoneUTC, username: root, password: 123456, driver: com.mysql.cj.jdbc.Driver } }, { name: user_mongo, type: custom, factory: org.apache.calcite.adapter.mongodb.MongoSchema$Factory, operand: { host: localhost, port: 27017, database: user_db, collection: user_info } } ] }几个关键配置给大家解释清楚避免踩坑defaultSchema默认查询的 Schema可省略查询时需指定 Schema 名称如 ecommerce.order、user_mongo.user_info。factory对应数据源的适配器工厂类Calcite 已为主流数据源提供现成工厂自定义数据源需实现自己的 Factory。operand数据源连接参数根据数据源类型不同配置不同参数如 MySQL 的 jdbcUrl、MongoDB 的 host/port。2.3 Spring Boot 集成 Calcite MyBatis Plus 核心配置这一步是核心主要分两步走配置好 Calcite 数据源让 MyBatis Plus 用上这个数据源顺便把 mapper 扫描、分页插件这些基础参数配好。直接上配置类代码import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.apache.calcite.jdbc.CalciteConnection; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; Configuration // MyBatis Plus mapper 接口扫描指定 mapper 包路径 MapperScan(basePackages com.example.calcite.mapper) public class CalciteMybatisPlusConfig { // 1. 配置 Calcite 数据源核心与原逻辑一致 Bean public DataSource calciteDataSource() throws Exception { Properties props new Properties(); props.setProperty(model, classpath:calcite-model.json); Connection connection DriverManager.getConnection(jdbc:calcite:, props); CalciteConnection calciteConnection connection.unwrap(CalciteConnection.class); return calciteConnection.getDataSource(); } // 2. 配置 MyBatis Plus 的 SqlSessionFactory指定使用 Calcite 数据源 Bean public SqlSessionFactory sqlSessionFactory(DataSource calciteDataSource) throws Exception { MybatisSqlSessionFactoryBean sessionFactory new MybatisSqlSessionFactoryBean(); // 注入 Calcite 数据源 sessionFactory.setDataSource(calciteDataSource); // 配置 mapper.xml 文件路径如果使用 XML 方式编写 SQL sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/*.xml)); // 配置 MyBatis Plus 全局参数可选 org.apache.ibatis.session.Configuration configuration new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰 sessionFactory.setConfiguration(configuration); // 注入 MyBatis Plus 插件如分页插件 sessionFactory.setPlugins(mybatisPlusInterceptor()); return sessionFactory.getObject(); } // 3. MyBatis Plus 分页插件可选复杂查询分页用 Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 适配 Calcite 兼容的 MySQL 语法 return interceptor; } // 4. 配置事务管理器可选需要事务支持时添加 Bean public PlatformTransactionManager transactionManager(DataSource calciteDataSource) { return new DataSourceTransactionManager(calciteDataSource); } }核心逻辑给大家捋一捋先通过 Calcite 创建统一的数据源再把它注入到 MyBatis Plus 的 SqlSessionFactory 里。这样一来咱们后续写代码就完全是 MyBatis Plus 的熟悉风格了不管是 Mapper 接口还是 XML 映射文件都能直接用跨数据源查询的复杂逻辑全交给 Calcite 处理。2.4 核心查询实现MyBatis Plus 风格接下来就是大家最熟悉的查询实现环节了我用 MyBatis Plus 最常用的“Mapper 接口注解”和“XML”两种方式来演示还是以 MySQL 订单表和 MongoDB 用户表的关联查询为例大家可以根据自己的习惯选定义实体类对应跨数据源查询结果可使用 lombok 简化代码import lombok.Data; Data public class UserOrderVO { private String orderId; // 订单 ID来自 MySQL private String orderTime; // 下单时间来自 MySQL private BigDecimal amount; // 订单金额来自 MySQL private String userName; // 用户名来自 MongoDB private String phone; // 手机号来自 MongoDB private String userId; // 用户 ID关联字段 }2. 定义 Mapper 接口MyBatis Plus 风格无需编写实现类import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; // 继承 BaseMapper获得 MyBatis Plus 基础 CRUD 能力 public interface UserOrderMapper extends BaseMapperUserOrderVO { // 注解方式编写跨数据源关联 SQL Select(SELECT o.order_id AS orderId, o.order_time AS orderTime, o.amount, u.user_name AS userName, u.phone, o.user_id AS userId FROM ecommerce.order o // ecommerceMySQL 的 Schemaorder订单表 JOIN user_mongo.user_info u // user_mongoMongoDB 的 Schemauser_info用户表 ON o.user_id u.user_id WHERE o.user_id #{userId}) ListUserOrderVO queryUserOrderByUserId(Param(userId) String userId); }3. 编写 Service 层import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import java.util.List; Service public class UserOrderServiceImpl extends ServiceImplUserOrderMapper, UserOrderVO implements UserOrderService { Override public ListUserOrderVO getUserOrderByUserId(String userId) { // 调用 Mapper 接口方法实现跨数据源查询 return baseMapper.queryUserOrderByUserId(userId); // 若使用 XML 方式return baseMapper.queryUserOrderByUserIdWithXml(userId); } }4. 编写 Controller 层import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; RestController public class CrossDataSourceQueryController { Autowired private UserOrderService userOrderService; GetMapping(/user/order/{userId}) public ListUserOrderVO queryUserOrder(PathVariable String userId) { // 调用 Service 方法返回跨数据源查询结果 return userOrderService.getUserOrderByUserId(userId); } }最后再划 3 个重点确保大家少走弯路实体类字段要和查询结果列名对应用别名适配下划线转驼峰更省心Mapper 接口继承 BaseMapper 后MyBatis Plus 的分页、条件构造器这些功能都能直接用复杂查询也能轻松搞定咱们写的都是标准 SQLCalcite 会自动解析适配不同数据源完全不影响大家原来的开发习惯。三、深度解析Calcite 的经典使用场景讲完了集成步骤再跟大家深度拆解下 Calcite 的经典落地场景。毕竟技术最终要服务于业务这些场景都是我在实际项目中常用到的拿来就能用第一个经典场景是多系统数据融合查询这也是企业级中台的核心需求。做企业级中台的小伙伴肯定深有体会大型企业里数据都是分散的——订单系统用 MySQL用户系统用 MongoDB 存行为数据库存系统用 PostgreSQL。要是想做“用户-订单-库存”全链路分析传统做法得分别调三个系统的接口再在业务层手动整合数据不仅效率低还容易出错。用 Calcite 分别适配这三个数据源后只要写一套标准 SQL 就能实现跨数据源关联查询咱们用 Spring Boot 3 搭好接口服务业务层完全不用管数据存在哪专注核心业务逻辑就行亲测开发效率能提升 50%以上再也不用写重复的接口调用和数据整合代码而且 Calcite 的查询优化器会自动优化关联逻辑查询效率也能跟上。第二个场景是实时数据与离线数据联动查询做电商的小伙伴应该经常遇到这类需求。比如实时订单数据存在 Kafka 里历史订单数据存在 Hive 里运营需要实时查看“今日订单近 30 天历史订单”的汇总数据来做实时监控和决策。这种情况不用麻烦地把 Kafka 数据同步到 Hive也不用把 Hive 数据同步到实时库直接用 Calcite 的 Kafka 适配器calcite-kafka和 Hive 适配器calcite-hive就能把实时流数据和离线数据放到同一个查询体系里写一条 SQL 就能实现“实时离线”数据的联合查询既省了大量数据同步成本又能兼顾实时性和准确性还支持增量查询。第三个场景是自定义数据源适配主要解决特殊格式数据查询的难题。企业里总有很多 CSV、Excel、Parquet 格式的文件数据传统做法是先把这些文件导入数据库才能查询步骤又多又耗时尤其是临时做数据分析的时候导入数据库的成本太高了。而 Calcite 内置了文件适配器calcite-file支持直接查询这些文件数据根本不用导入数据库。咱们再结合 Spring Boot 3 的文件上传功能还能实现“文件上传后直接用 SQL 查询”的需求临时分析数据超方便。如果有企业内部的特殊格式文件比如自定义的二进制文件也可以自己实现 Calcite 的 SchemaFactory 和 TableFactory 接口写个自定义适配器就能适配这些特殊数据源了。四、避坑指南集成注意事项与优化建议4.1 这些坑一定要避开适配器版本要统一Calcite 核心依赖和各数据源适配器的版本必须一致不然很容易出现类加载异常这个坑我踩过大家一定要注意。模型文件配置要规范Schema 名称、表名要清晰别重复数据源的地址、端口、账号密码这些连接参数一定要准确错一个就会连接失败。要考虑数据源性能跨数据源查询的性能取决于最慢的那个数据源所以要确保每个数据源自身性能没问题不然会拖慢整个查询。4.2 优化小技巧查询更快更稳启用 Calcite 缓存配置一下 Calcite 的元数据缓存和查询计划缓存能减少重复解析和元数据查询的时间提升查询效率。优化 SQL 写法尽量避免复杂的多表关联能把过滤条件下推到数据源的就尽量下推。虽然 Calcite 会自动优化但手动优化后的效果会更好。自定义优化规则如果是特别复杂的业务场景可以自己实现 Calcite 的 OptimizerRule 接口写自定义的查询优化规则进一步提升查询效率。五、本文总结最后总结一下对于熟悉 Spring Boot 3 的咱们来说集成 Calcite 的关键就是理解它“统一查询”的核心思想把模型文件写对、核心 Bean 配置好就能快速实现多数据源查询能力了。