# jdbc-mongodb-driver **Repository Path**: inrgihc/jdbc-mongodb-driver ## Basic Information - **Project Name**: jdbc-mongodb-driver - **Description**: dbswitch所使用的mongodb的jdbc驱动jar项目 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-09 - **Last Updated**: 2026-03-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # jdbc-mongodb-driver ## 一、介绍 dbswitch&sqlrest 项目所使用的 MongoDB 的 JDBC 驱动项目。该驱动通过实现 JDBC 标准,将 MongoDB 以关系型数据库的方式对外暴露,使得标准 SQL 工具和框架可以直接操作 MongoDB 数据库。 - dbswich 托管项目地址:https://gitee.com/inrgihc/dbswitch - sqlrest 托管项目地址:https://gitee.com/inrgihc/sqlrest ## 二、功能特性 ### 2.1 核心功能 - **JDBC 标准接口实现**:完全实现 `java.sql.Driver`、`Connection`、`Statement`、`PreparedStatement`、`ResultSet` 等 JDBC 核心接口 - **MongoDB Shell 脚本执行**:通过 GraalVM JavaScript 引擎支持执行 MongoDB Shell 语法 - **动态元数据扫描**:自动扫描集合文档结构,推导 Schema 信息,支持 JSON Schema 验证器 - **嵌套文档展开(Expand)**:支持将嵌套的 MongoDB 文档自动展平为关系型表格结构 - **集合间关系发现**:通过 ObjectId 反向查询自动发现集合间的外键引用关系 ### 2.2 高级特性 - **扫描策略(ScanStrategy)**: - `fast`:扫描前 100 条文档快速建立元数据 - `medium`:扫描前 300 条文档平衡性能和准确性(默认) - `full`:全量扫描获取完整 Schema - **结果集展开模式**: - `expand=true`:嵌套对象展平为 `parent.child` 形式的列(默认) - `expand=false`:保持原始嵌套结构 - **参数化查询支持**:支持 `?` 占位符的 PreparedStatement 查询和更新操作 - **SSL/TLS 连接**:支持通过 `trustStore` 和 `trustStorePassword` 参数配置安全连接 ## 三、代码结构 ``` com.gitee.jdbc.mongodb ├── JdbcDriver.java # JDBC 驱动入口,实现 java.sql.Driver ├── MongoConnection.java # JDBC Connection 实现,管理 GraalVM JS 上下文 ├── MongoPreparedStatement.java # PreparedStatement 实现,支持参数绑定和 SQL 转译 ├── MongoDatabaseMetaData.java # DatabaseMetaData 实现,提供元数据查询接口 ├── MongoResultSetMetaData.java # ResultSetMetaData 实现 ├── ScanStrategy.java # 扫描策略枚举(fast/medium/full) ├── DriverPropertyInfoHelper.java # 驱动属性信息辅助类 ├── GraalConvertor.java # GraalVM 数据类型转换器 ├── Util.java # 工具类 │ ├── resultSet/ # 结果集实现 │ ├── ResultSetIterator.java # 核心结果集迭代器,预读 300 条建立列元数据 │ ├── ArrayResultSet.java # 数组类型结果集 │ ├── ObjectAsResultSet.java # 对象类型结果集 │ └── OkResultSet.java # 操作结果状态结果集 │ ├── structure/ # 元数据模型 │ ├── MetaDatabase.java # 数据库元数据 │ ├── MetaCollection.java # 集合元数据 │ ├── MetaField.java # 字段元数据 │ ├── MetaIndex.java # 索引元数据 │ ├── MetaObject.java # 文档对象元数据 │ └── MetaReference.java # 集合引用关系 │ └── wrappers/ # MongoDB 客户端包装类 ├── WrappedMongoClient.java # 客户端包装 ├── WrappedMongoDatabase.java # 数据库包装(实现 ProxyObject) ├── WrappedMongoCollection.java # 集合包装 └── WrappedFindIterable.java # 查询结果包装 ``` ### 3.1 核心类说明 | 类名 | 说明 | |------|------| | `JdbcDriver` | 驱动入口类,解析连接 URL,创建连接,注册驱动 | | `MongoConnection` | 连接实现,创建和管理 GraalVM JavaScript 执行上下文 | | `MongoPreparedStatement` | 核心语句类,将 SQL/MongoDB Shell 命令转译为 MongoDB 操作,支持 `?` 占位符 | | `MongoDatabaseMetaData` | 元数据查询实现,提供 `getCatalogs()`、`getTables()`、`getColumns()`、`getPrimaryKeys()` 等方法 | | `ResultSetIterator` | 结果集迭代器,预读文档建立列结构,支持 expand 模式 | | `WrappedMongoDatabase` | 实现了 `ProxyObject` 接口,使 JavaScript 可以 `db.collectionName` 方式访问集合 | ## 四、使用示例 ### 4.1 基本连接 ```java import java.sql.*; // 加载驱动 Class.forName("com.gitee.jdbc.mongodb.JdbcDriver"); // 连接 URL 格式 String url = "jdbc:mongodb://host:port/database?options"; // 无认证连接 Connection conn = DriverManager.getConnection("jdbc:mongodb://localhost:27017/admin"); // 带认证连接 Connection conn = DriverManager.getConnection( "jdbc:mongodb://localhost:27017/admin?authSource=admin&authMechanism=SCRAM-SHA-1", "username", "password" ); ``` ### 4.2 查询元数据 ```java // 获取所有数据库 DatabaseMetaData metaData = conn.getMetaData(); ResultSet catalogs = metaData.getCatalogs(); while (catalogs.next()) { String dbName = catalogs.getString("TABLE_CAT"); System.out.println("Database: " + dbName); } // 获取指定数据库的所有集合 ResultSet tables = metaData.getTables("test", null, null, null); while (tables.next()) { String tableName = tables.getString("TABLE_NAME"); System.out.println("Collection: " + tableName); } // 获取集合的字段信息 ResultSet columns = metaData.getColumns("test", null, "t_person", null); while (columns.next()) { String colName = columns.getString("COLUMN_NAME"); String typeName = columns.getString("TYPE_NAME"); int dataType = columns.getInt("DATA_TYPE"); System.out.println(String.format("Column: %s, Type: %s (%d)", colName, typeName, dataType)); } ``` ### 4.3 MongoDB Shell 查询 ```java Statement stmt = conn.createStatement(); // 使用 MongoDB Shell 语法查询 ResultSet rs = stmt.executeQuery("test.t_person.find({})"); while (rs.next()) { System.out.println(rs.getString("name") + ", " + rs.getInt("score")); } // 带条件查询 ResultSet rs = stmt.executeQuery("test.t_person.find({score: {$gt: 80}})"); // 使用 getCollection 方法 ResultSet rs = stmt.executeQuery("test.getCollection('t_person').find({})"); stmt.close(); ``` ### 4.4 插入数据 ```java Statement stmt = conn.createStatement(); // 插入单条文档 stmt.executeUpdate("test.t_person.insert({\"_id\": 1, \"name\": \"Alice\", \"score\": 90})"); // 插入多条文档 stmt.executeUpdate("test.t_person.insertMany([" + "{item: \"journal\", qty: 25, status: \"A\"}," + "{item: \"notebook\", qty: 50, status: \"A\"}" + "])"); // 使用 insertOne(推荐) stmt.executeUpdate("test.t_person.insertOne({\"_id\": 2, \"name\": \"Bob\", \"score\": 85})"); ``` ### 4.5 更新数据 ```java // 使用 PreparedStatement 更新 PreparedStatement ps = conn.prepareStatement("update test.t_person"); Map filter = new HashMap<>(); filter.put("_id", 1); ps.setObject(1, filter); ps.executeUpdate(); // 或者使用 MongoDB Shell 语法 Statement stmt = conn.createStatement(); stmt.executeUpdate("test.t_person.updateOne({_id: 1}, {$set: {score: 95}})"); ``` ### 4.6 删除数据 ```java // 使用 PreparedStatement 删除 PreparedStatement ps = conn.prepareStatement("delete from test.t_person"); Map filter = new HashMap<>(); filter.put("_id", 1); ps.setObject(1, filter); ps.executeUpdate(); // 或者使用 MongoDB Shell 语法 Statement stmt = conn.createStatement(); stmt.executeUpdate("test.t_person.deleteOne({_id: 1})"); ``` ### 4.7 参数化查询 ```java // 使用 ? 占位符查询 PreparedStatement ps = conn.prepareStatement("test.t_person.find({name: ?})"); ps.setString(1, "Alice"); ResultSet rs = ps.executeQuery(); while (rs.next()) { System.out.println(rs.getString("name") + ", " + rs.getInt("score")); } // 多参数查询 PreparedStatement ps = conn.prepareStatement("test.t_person.find({name: ?, score: ?})"); ps.setString(1, "Alice"); ps.setInt(2, 90); ResultSet rs = ps.executeQuery(); // 参数化插入 PreparedStatement ps = conn.prepareStatement("test.t_person.insertOne({_id: ?, name: ?, score: ?})"); ps.setInt(1, 100); ps.setString(2, "Charlie"); ps.setDouble(3, 88.5); ps.execute(); ``` ## 五、连接参数说明 ### 5.1 URL 格式 ``` jdbc:mongodb://[username:password@]host1[:port1][,host2[:port2],...][/database][?options] ``` ### 5.2 自定义参数 | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `scan` | String | `fast` | 元数据扫描策略:`fast`(100条)、`medium`(300条)、`full`(全量) | | `expand` | Boolean | `true` | 是否展开嵌套文档为扁平结构 | | `sort` | Boolean | `false` | 是否对结果集字段进行排序 | | `trustStore` | String | - | SSL 信任库路径 | | `trustStorePassword` | String | - | SSL 信任库密码 | ### 5.3 示例 URL ```java // 基本连接 jdbc:mongodb://localhost:27017/admin // 带扫描策略 jdbc:mongodb://localhost:27017/admin?scan=medium // 关闭嵌套展开 jdbc:mongodb://localhost:27017/admin?expand=false // SSL 连接 jdbc:mongodb://localhost:27017/admin?trustStore=/path/to/keystore.jks&trustStorePassword=changeit // 完整配置 jdbc:mongodb://user:password@localhost:27017/admin?authSource=admin&authMechanism=SCRAM-SHA-1&scan=medium&expand=true ``` ## 六、编译 ### 6.1 环境要求 - **JDK**: >= 1.8(建议使用 JDK 1.8) - **Maven**: >= 3.6 > 提示:Maven 仓库默认在国外,国内使用较慢,可以更换为阿里云仓库。参考教程:[配置阿里云的仓库教程](https://www.runoob.com/maven/maven-repositories.html) ### 6.2 编译步骤 ```bash mvn clean package -DskipTests=true ``` ### 6.3 编译产物 编译完成后,会生成驱动 jar 文件 `target/mongodb-jdbc-driver-4.10.2-jar-with-dependencies.jar`(约 28MB)。 将该 jar 文件复制到 dbswitch 项目的 `dbswitch/drivers/mongodb/mongo-4.10` 目录下即可。 ## 七、注意事项 1. **元数据扫描性能**: - `fast` 模式仅扫描前 100 条文档,适合快速查看 - `full` 模式扫描所有文档,耗时较长,适合生产环境元数据导出 - 建议生产环境使用 `medium` 模式平衡性能和准确性 2. **嵌套文档处理**: - 默认开启 `expand=true` 模式,会将嵌套对象展平为 `parent.child` 列 - 深度嵌套文档可能产生大量列,建议保持适当的文档结构 - 关闭 `expand` 后,嵌套对象将以 JSON 字符串形式返回 3. **集合间关系**: - 驱动会自动通过 ObjectId 发现集合间的引用关系 - 这种发现是启发式的,可能存在误判,需要人工确认 4. **GraalVM JS 引擎**: - 驱动使用 GraalVM JavaScript 引擎执行 MongoDB Shell 脚本 - 某些高级 MongoDB Shell 语法可能不完全支持 - 建议优先使用标准 MongoDB 查询语法 5. **JDBC 兼容性**: - 本驱动实现了 JDBC 标准接口,但 MongoDB 本身是文档数据库,部分关系型特性(如事务、外键约束)可能不完全支持 - 使用标准 JDBC 工具(如 DBeaver)时,需要针对文档数据库特点进行适配 6. **参数绑定**: - 支持 `?` 占位符的 PreparedStatement - 参数按位置绑定(从 1 开始) - 复杂类型建议使用 `ps.setObject()` 方法传入 Map 或 Document 7. **SSL 连接**: - 使用 SSL/TLS 时需要提供正确的 trustStore 配置 - 验证失败请检查证书链和密码 ## 八、问题反馈 如果您看到并使用了本工具,或您觉得本工具对您有价值,请为此项目**点个赞**,以表示对本项目的支持,多谢!如果您在使用时遇到了 bug,欢迎在 issue 中反馈。也可扫描下方二维码入群讨论:(加好友请注明:"程序交流") ![structure](https://gitee.com/inrgihc/dbswitch/raw/master/docs/images/weixin.PNG)