JQuick-SQL "数据源 SPI"辨析:应用适配器与 Function SPI 的正确边界
Meta 描述:澄清 jquick-sql 不提供数据源 SPI;外部接入应由应用适配器或 jquick-connector 完成,项目现有 SPI 聚焦 SQL 函数扩展。
标签:jquick-sql、Function SPI、ServiceLoader、应用适配器、异构数据源联邦查询、轻量级 SQL 引擎、Java 跨库查询
官网示例:
- FORMULAS 示例页:https://www.jquick.org/jquick-sql
- github 地址:https://github.com/paohaijiao/jquick-sql
前言
"数据源 SPI"这一说法容易让人误以为 jquick-sql 可通过插件直接连接 JDBC、CSV、NoSQL 或 REST。根据项目现有边界,这种理解并不准确:jquick-sql 不提供外部数据源 SPI。它的外部数据接入应由应用层或 jquick-connector 完成;项目可验证的 SPI 方向是 SQL 函数扩展。
先纠正命名:没有外部数据源 SPI
JQuickDataSourceManager 管理的是已注册的 JQuickDataSet 表,包括注册、替换、获取、清理和统计,并不是 JDBC/CSV/REST 驱动插件框架。外部来源的数据应先由适配器读取、清洗、转换为 JQuickRow / JQuickDataSet,再通过 registerTable 进入查询引擎。
因此,不要设计或调用不存在的 DataSourceProvider、registerConnector、registerJdbcDriver 等 jquick-sql API。
应用层适配器的推荐设计
可在业务工程中定义自己的适配器接口,例如 load() 返回 JQuickDataSet。每个实现负责一种来源的认证、连接、分页、字段映射与错误治理,调用侧仅负责注册和执行 SQL。这样不会把外部协议耦合到查询内核。
适配器输出应具备明确的表名、列元数据、业务主键和刷新时间。多来源场景要统一类型、时区、枚举和空值规则,保证异构数据源联邦查询的结果口径可靠。
项目现有的 Function SPI
项目资源目录中存在 META-INF/services/com.github.paohaijiao.function.core.JQuickMethodFunctionProvider,并通过 Java ServiceLoader 发现函数 Provider。README 展示的扩展方式是继承 JQuickBaseFunctionFunctionProvider 并实现 invoke(List<Object> args),用于为 SQL 增加函数,而不是加载外部数据源。
函数 SPI 适合封装文本、日期、业务编码等纯计算逻辑。涉及网络、数据库或文件读取的操作不应伪装成 SQL 函数,以免破坏查询可预测性和安全边界。
代码案例
java
import com.github.paohaijiao.engine.JQuickSQL;
import com.github.paohaijiao.statement.JQuickColumnMeta;
import com.github.paohaijiao.statement.JQuickDataSet;
import com.github.paohaijiao.statement.JQuickRow;
import java.util.Arrays;
import java.util.List;
public class AdapterBoundaryDemo {
public static void main(String[] args) {
// 示例适配器仅代表应用层实现;不是 jquick-sql 内置 SPI。
JQuickDataSet customerData = new CustomerAdapter().load();
JQuickSQL sql = JQuickSQL.embedded();
try {
sql.registerTable("customers", customerData);
sql.execute("SELECT region, COUNT(*) AS customer_count " +
"FROM customers GROUP BY region").printTable();
} finally {
sql.shutdown();
}
}
static class CustomerAdapter {
JQuickDataSet load() {
// 实际项目中,在这里通过已有 DAO、HTTP 客户端或 jquick-connector 获取外部数据。
return new JQuickDataSet(Arrays.asList(
new JQuickColumnMeta("id", Long.class, "customers"),
new JQuickColumnMeta("region", String.class, "customers")
), Arrays.asList(
row("id", 1L, "region", "华东"),
row("id", 2L, "region", "华南")
));
}
}
private static JQuickRow row(Object... values) {
JQuickRow row = new JQuickRow();
for (int i = 0; i < values.length; i += 2) row.put((String) values[i], values[i + 1]);
return row;
}
}
常见问题
**jquick-sql 是否有数据源 SPI?**没有可作为外部 JDBC、CSV、NoSQL、REST 连接器机制的数据源 SPI。
**项目里能扩展什么 SPI?**可验证的是 Function SPI,用于通过 ServiceLoader 扩展 SQL 函数。
**外部来源应该放在哪里实现?**在应用层或 jquick-connector 中读取并转换为 JQuickDataSet,再调用 registerTable。
总结与拓展
明确"适配器在应用层、函数 SPI 在 SQL 层"能避免架构误用。jquick-sql 负责已注册数据集上的 Java 分布式 SQL 查询引擎能力;外部协议、凭证和采集策略由业务工程掌握,二者结合更适合中小企业渐进式建设数据分析能力。
Core Advantage
Keeps source integration explicit in application adapters while extending SQL computation through a real Function SPI.
Applicable Scenarios
Custom business functions, adapter-based ingestion, embedded reporting services, and controlled multi-source analytical workflows.