Exposed R2DBC ConnectionFactory 使用指南:从 URL 隐式解析到显式连接工厂配置
ORM后端数据存储【免费下载链接】ExposedKotlin SQL Framework项目地址https://gitcode.com/gh_mirrors/ex/Exposed点击查看免费下载本文以 JetBrains Exposed 的exposed-r2dbc模块为核心系统讲解如何通过R2dbcDatabase.connect()与 R2DBC 的ConnectionFactory建立响应式数据库连接。你将掌握三种连接方式——URL 隐式解析、手动构建ConnectionFactoryOptions、显式传入ConnectionFactory——并理解其背后的方言解析、重试事务与suspendTransaction使用要点可直接用于 H2、PostgreSQL、MySQL、MariaDB、Oracle、SQL Server 等数据库的非阻塞访问。为什么 R2DBC 需要一个 ConnectionFactory在 JDBC 世界中DataSource是连接获取的统一入口而在 R2DBCReactive Relational Database Connectivity中这个角色由io.r2dbc.spi包中的ConnectionFactory承担。它是 JDBCDataSource的响应式等价物负责产生非阻塞的Connection实例为基于 Reactor 与 Kotlin 协程的数据库访问提供基础。Exposed 的exposed-r2dbc模块正是围绕这一抽象设计的通过R2dbcDatabase.connect()函数你可以用最少量的样板代码把一个 R2DBC 连接源接入 Exposed 的 DSL / DAO 层。值得注意的是R2dbcDatabase.connect()并不会立即建立真实连接而是记录下建立连接所需的全部细节等到某个事务真正需要连接时才实例化——这一点在 R2dbcDatabase.kt 中所有connect()重载的 KDoc 中都有明确说明。方式一通过 URL 隐式连接最简单的方式是直接把 R2DBC 连接 URL 传给R2dbcDatabase.connect()。此时字符串会被解析并构造出一个ConnectionFactoryOptions对象该对象持有与ConnectionFactory相关的全部配置状态val h2db R2dbcDatabase.connect(r2dbc:h2:mem:///test)这个调用等价于仅传入配置块的R2dbcDatabase.connect()重载import io.r2dbc.spi.IsolationLevel import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase val database R2dbcDatabase.connect { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED setUrl(r2dbc:h2:mem:///test;DB_CLOSE_DELAY-1;) }其中defaultMaxAttempts事务失败时的最大重试次数。该属性定义在 DatabaseConfig.kt 中默认值为3且构建时通过require(builder.defaultMaxAttempts 0)强制要求至少为 1 次尝试defaultR2dbcIsolationLevel默认事务隔离级别不设置时采用数据库特定级别可参考R2dbcDatabase.getDefaultIsolationLevel()如 MySQL 默认REPEATABLE_READ其余多数数据库默认READ_COMMITTEDsetUrl(...)解析 R2DBC 连接 URL 并写入connectionFactoryOptions。URL 的期望格式为r2dbc:driver[:protocol]://[user:password]host[:port][/path][?optionvalue]。更多数据库的 URL 示例可以参考仓库中的 R2DBCDatabases.kt它覆盖了 H2内存库与文件库、MySQL、Oracle、PostgreSQL、MariaDB、SQL Server 的完整写法例如// PostgreSQL R2dbcDatabase.connect( url r2dbc:postgresql://db:5432/test, driver postgresql, user user, password password ) // SQL Server R2dbcDatabase.connect( r2dbc:mssql://localhost:32768;databaseNametest, driver sqlserver, user user, password password )当 URL 未显式携带driver参数时R2dbcDatabase会根据 URL 前缀从内部映射表推导驱动名。从源码看该映射位于 R2dbcDatabase.kt 的driverMapping包含r2dbc:h2 → h2、r2dbc:postgresql → postgresql、r2dbc:mysql → mysql、r2dbc:mariadb → mariadb、r2dbc:oracle → oracle、r2dbc:mssql → sqlserver、r2dbc:pool → pool若前缀匹配失败会抛出 Database driver not found 异常。connect()内部还会把非空的user、password写入ConnectionFactoryOptions.USER/PASSWORD。方式二手动构建 ConnectionFactoryOptions当你需要更细粒度地控制连接选项时可以通过R2dbcDatabaseConfig.connectionFactoryOptions构建器手工设置ConnectionFactoryOptions状态。构建器在 R2dbcDatabaseConfig.kt 中实现connectionFactoryOptions(block)会先基于当前状态复制一个ConnectionFactoryOptions.Builder执行你的配置块后再构建为新状态并回写。2.1 与 URL 并存使用connect()既接收 URL又通过databaseConfig补充额外选项。URL 负责解析驱动、协议、库名等核心信息构建器内补充的参数如 H2 的DB_CLOSE_DELAY会被合并进最终状态import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val database R2dbcDatabase.connect( url r2dbc:h2:mem:///test;, databaseConfig R2dbcDatabaseConfig { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED connectionFactoryOptions { option(Option.valueOf(DB_CLOSE_DELAY), -1) } } )2.2 完全从零构建也可以完全不使用 URL而是逐项声明DRIVER、PROTOCOL、DATABASE等标准选项import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase val database R2dbcDatabase.connect { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED connectionFactoryOptions { option(ConnectionFactoryOptions.DRIVER, h2) option(ConnectionFactoryOptions.PROTOCOL, mem) option(ConnectionFactoryOptions.DATABASE, test) option(Option.valueOf(DB_CLOSE_DELAY), -1) } }2.3 预构建 ConnectionFactoryOptions 并复用你还可以先独立构造一个ConnectionFactoryOptions对象用它初始化自定义的R2dbcDatabaseConfig之后再随时传给R2dbcDatabase.connect()import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val options ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, h2) .option(ConnectionFactoryOptions.PROTOCOL, mem) .option(ConnectionFactoryOptions.DATABASE, test) .option(Option.valueOf(DB_CLOSE_DELAY), -1) .build() val databaseConfig R2dbcDatabaseConfig { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED connectionFactoryOptions options } val database R2dbcDatabase.connect(databaseConfig databaseConfig)这种方式适合把连接配置与业务初始化代码解耦例如集中管理多套环境的连接选项。方式三显式传入 ConnectionFactory除了隐式发现R2dbcDatabase.connect()也支持手动编程式连接工厂发现直接提供一个显式的ConnectionFactory绕过 URL 解析流程。3.1 使用通用 SPI 工厂通过io.r2dbc.spi.ConnectionFactories.get(options)获取工厂后传入import io.r2dbc.spi.ConnectionFactories import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.core.vendors.H2Dialect import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val options ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, h2) .option(ConnectionFactoryOptions.PROTOCOL, mem) .option(ConnectionFactoryOptions.DATABASE, test) .option(Option.valueOf(DB_CLOSE_DELAY), -1) .build() val connectionFactory ConnectionFactories.get(options) val database R2dbcDatabase.connect( connectionFactory connectionFactory, databaseConfig R2dbcDatabaseConfig { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED explicitDialect H2Dialect() } )重要提示使用显式ConnectionFactory时必须为R2dbcDatabaseConfig.explicitDialect设置一个值。这是因为方言无法再从ConnectionFactory或其配置选项中可靠地解析显式声明可以避免方言解析失败导致后续事务异常。3.2 使用数据库专用工厂为了更精细的定制也可以直接使用数据库特有的连接工厂与配置构建器例如 H2 的H2ConnectionFactoryimport io.r2dbc.h2.H2ConnectionConfiguration import io.r2dbc.h2.H2ConnectionFactory import io.r2dbc.h2.H2ConnectionOption import io.r2dbc.spi.IsolationLevel import org.jetbrains.exposed.v1.core.vendors.H2Dialect import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val connectionFactory H2ConnectionFactory( H2ConnectionConfiguration.builder() .inMemory(test) .property(H2ConnectionOption.DB_CLOSE_DELAY, -1) .build() ) val database R2dbcDatabase.connect( connectionFactory connectionFactory, databaseConfig R2dbcDatabaseConfig { defaultMaxAttempts 1 defaultR2dbcIsolationLevel IsolationLevel.READ_COMMITTED explicitDialect H2Dialect() } )这类数据库专用对象的创建与传递方式与通用 R2DBC SPI 对象完全一致。背后原理doConnect 与方言解析从源码层面看所有R2dbcDatabase.connect()重载最终都汇聚到私有函数doConnect()见 R2dbcDatabase.kt其核心逻辑可以概括为读取config.connectionFactoryOptions作为状态持有者解析explicitVendor若配置了explicitDialect优先使用它H2 特殊处理为H2Dialect.dialectName否则回退到options.dialectName若未显式传入connectionFactory则通过ConnectionFactories.get(options)创建构造R2dbcDatabase实例其连接器为R2dbcConnectionImpl(factory.create(), explicitVendor, config.typeMapping)依据选项重建url与urlMode并向TransactionManager注册该实例。方言解析的细节集中在 ConnectionFactoryOptionsUtils.ktdialect扩展属性优先读取ConnectionFactoryOptions.DRIVER若其值为pool连接池包装则回退到PROTOCOL并截取冒号前缀随后映射到H2Dialect、PostgreSQLDialect、MysqlDialect、MariaDBDialect、OracleDialect、SQLServerDialect无法识别时抛出 Unsupported driver dialect detected 异常。此外H2 特有的MODE参数会通过urlMode解析出来供 core 层的h2Mode属性使用。同时R2dbcDatabase的伴生对象在初始化时注册了上述六种方言及其DatabaseDialectMetadata并允许通过registerDialectMetadata()扩展自定义元数据实现。连接后使用 suspendTransaction 执行事务无论采用上述哪种方式连接注册好连接源后你就可以使用suspendTransaction执行基于协程的数据库操作对应 JDBC 路径下的transaction。它定义在 Transactions.kt 中import org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction suspendTransaction { // DSL/DAO 操作 }事务解析顺序为显式传入的db参数 → 当前已存在事务关联的数据库 →TransactionManager.primaryDatabase注册的默认数据库均无匹配时抛出IllegalStateException。suspendTransaction还支持transactionIsolation、readOnly、maxAttempts、queryTimeout等高级参数详见 Transactions.md 的 Advanced parameters and usage 一节事务执行失败时会按maxAttempts与重试间隔策略自动重试并确保语句与连接资源被正确清理。小结与最佳实践连接方式适用场景关键点URL 隐式解析快速接入、单数据库一条 URL 即可驱动可自动映射手动connectionFactoryOptions需要补充驱动特有选项可与 URL 并存也可完全手写预构建ConnectionFactoryOptions配置复用、多环境管理先建 options 再建 config显式ConnectionFactory已有工厂实例、编程式发现必须设置explicitDialect数据库专用工厂需要数据库特有的构建器如H2ConnectionFactoryH2ConnectionConfiguration实践建议使用显式ConnectionFactory时务必同步设置explicitDialect否则方言解析失败会直接抛出异常连接操作本身是惰性的R2dbcDatabase.connect()不建立真实连接实际连接在首个事务需要时才创建因此可以放心地在应用启动阶段注册若使用连接池URL 前缀r2dbc:pool方言解析会回退到PROTOCOL请确保协议选项中携带可识别的驱动名对 H2 内存库可通过DB_CLOSE_DELAY-1保持数据库在连接关闭后不销毁便于测试场景复用。延伸阅读Working with DataSourceJDBC 路径下对应的DataSource接入方式TransactionssuspendTransaction的嵌套事务、savepoint 与高级参数R2dbcDatabase.ktconnect()全部重载、驱动映射与方言注册R2dbcDatabaseConfig.ktsetUrl、connectionFactoryOptions构建器与默认隔离级别ConnectionFactoryOptionsUtils.ktConnectionFactoryOptions方言、URL 与 H2 模式的解析实现R2DBCDatabases.kt六种数据库的完整连接示例。赞分享ORM后端数据存储【免费下载链接】ExposedKotlin SQL Framework项目地址https://gitcode.com/gh_mirrors/ex/Exposed点击查看免费下载相关推荐mysql33/mysql连接字符串URL格式连接配置的终极使用指南mysql33/mysql连接字符串URL格式连接配置的终极使用指南 想要快速配置MySQL数据库连接mysql33/mysql项目提供了极其便捷的URL格后端数据库VASPsol 隐式溶剂模型使用指南从配置到优化VASPsol 隐式溶剂模型使用指南从配置到优化 核心配置参数详解 基础启用参数 作用说明控制溶剂化效应计算的开关 使用场景所有需要模拟溶剂环境的DFT计科学计算科研高性能计算JetBrains Exposed 数据库操作指南连接与配置详解JetBrains Exposed 数据库操作指南连接与配置详解 前言 JetBrains Exposed 是一个轻量级的 Kotlin SQL 框架它提供ORM后端数据存储上一篇仓颉multipart实现原理三RFC合规Content-Disposition解析器逐行注释完整指南下一篇theHarvester 配置与密钥管理指南api-keys、代理与 API 服务端保护创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考