- ORM
- 后端
- 数据存储
【免费下载链接】Exposed
Kotlin SQL Framework
导读:Exposed 是 Kotlin 生态中一款类型安全的 SQL 框架,它按功能拆分成了
exposed-core、exposed-jdbc、exposed-dao等多个独立模块,允许开发者按需引入。本文以仓库中的 exposed-modules-groovy-gradle 示例项目为骨架,系统讲解在 Groovy DSL 的 Gradle 工程中配置 Maven Central 仓库、声明最小依赖集、使用版本目录(version catalog)统一管理版本、选择传输层模块以及补充 JDBC 驱动与日志依赖的完整实操流程。读完本文,你将能在自己的 Groovy Gradle 项目中以最精简且规范的方式接入 Exposed,并理解每个依赖在框架中的真实作用。
示例项目定位:Groovy Gradle 下的 Exposed 依赖模板
在 Exposed 官方文档仓库中,snippets目录是一个包含多个可运行示例的多模块 Gradle 工程,其中exposed-modules-groovy-gradle子项目专为 Groovy DSL 的 Gradle 构建脚本而生。它的定位非常明确:
- 它是一个自动生成的 Groovy Gradle 工程,内部包含 Exposed 的核心依赖声明;
- 它的
build.gradle(Groovy DSL 写法)被官方主题文档 Adding dependencies 以「按行引用」的方式直接嵌入展示,作为 Groovy 语法的权威示例; - 它的入口代码是一个最小可运行的 Kotlin 主函数,用于验证依赖装配正确后整个工程能够正常编译与构建。
该子项目在仓库中的实际结构如下:
documentation-website/Writerside/snippets/exposed-modules-groovy-gradle/ ├── README.md # 项目说明与构建命令 └── src/ └── main/ └── kotlin/ └── com/ └── example/ └── Main.kt # 最小 Kotlin 入口:println("Hello World!")其中入口文件 Main.kt 的内容非常简洁:
package com.example fun main() { println("Hello World!") }这段代码本身不涉及任何 Exposed API,它的作用是作为构建验证的载体——只要./gradlew :exposed-modules-groovy-gradle:build能成功,就说明 Exposed 依赖已被正确解析并打进 classpath。
同时,exposed-modules-groovy-gradle被登记在 snippets 多模块工程的 settings.gradle.kts 中(include("exposed-modules-groovy-gradle")),因此它可以直接作为整个 Gradle 工程的一个子项目进行构建。
构建与运行:一条命令验证依赖装配
根据 exposed-modules-groovy-gradle/README.md 的说明,构建该示例的完整流程为:
- 打开终端,进入
snippets目录(即documentation-website/Writerside/snippets); - 执行以下命令:
./gradlew :exposed-modules-groovy-gradle:build其中:exposed-modules-groovy-gradle是 Gradle 对子项目的路径式任务定位语法。由于snippets是一个多模块工程(settings.gradle.kts中通过include(...)注册了exposed-dao、exposed-dsl、exposed-modules-kotlin-gradle、exposed-modules-groovy-gradle等十余个子项目),使用这种带项目路径前缀的写法可以精确指定只构建目标子项目,而不会触发无关模块的构建。
注意:
./gradlew是 Linux/macOS 下的 Gradle Wrapper 执行方式,Windows 下请使用gradlew.bat。Wrapper 脚本与gradle/wrapper目录已随仓库提供,无需本机预装 Gradle。
此外,整个 snippets 工程还支持run任务直接运行某个示例,例如:
./gradlew :exposed-dao:run不过对于 Groovy 依赖模板而言,build任务已经足够验证依赖的完整性与正确性。
Exposed 模块全景:从核心到扩展的依赖地图
Adding-dependencies.md是理解该 Groovy 示例项目依赖声明的核心文档。它指出:Exposed 被拆分为特定模块,给你只引入所需模块的灵活性。所有模块可归为四类,下面结合 Groovy 语法逐一说明。
核心模块(Core module)
任何 Exposed 应用都必须引入的模块只有一个:
| 模块 | 功能 |
|---|---|
exposed-core | 提供与数据库进行类型安全交互所需的基础组件与抽象,包含领域特定语言(DSL)API |
从仓库源码结构可以印证这一点:exposed-core是仓库中最大的模块,其 src/main/kotlin 下包含 104 个 Kotlin 文件,覆盖AbstractQuery、Table、Column、Query、SqlExpressionBuilder、Transaction等 DSL 核心构件;同时api/exposed-core.api文件完整记录了该模块对外暴露的全部 API 签名。可以说,exposed-core是 Exposed 的「地基」。
传输模块(Transport modules)
传输模块定义了 Exposed 与数据库通信的方式,并且互斥——你只能二选一:
| 模块 | 功能 |
|---|---|
exposed-jdbc | 基于 Java JDBC API 的传输层实现,提供 JDBC 支持 |
exposed-r2dbc | 提供响应式关系数据库连接(R2DBC)支持 |
官方文档明确强调:只需要一个传输模块——要么exposed-jdbc,要么exposed-r2dbc,不要同时引入两者。这是因为它们对应两套完全不同的底层连接模型(阻塞式 JDBC 与响应式 R2DBC),同时引入会造成依赖冗余与运行时行为的不确定性。
数据库访问模块(Database access module)
在exposed-core之上,Exposed 提供了一个可选的高层数据访问模块:
| 模块 | 功能 |
|---|---|
exposed-dao | 提供数据访问对象(DAO)API,基于exposed-core构建,提供更高级的数据抽象 |
需要注意其约束:exposed-dao要求exposed-jdbc作为传输层,且与exposed-r2dbc不兼容。因此如果你计划使用 R2DBC 响应式方案,就不能同时使用 DAO API,而应回到 DSL 层。
扩展模块(Extension modules)
扩展模块为 Exposed 补充了数据类型、加密、日期时间等能力,全部按需引入:
| 模块 | 功能 |
|---|---|
exposed-crypt | 提供加密列类型,支持在客户端编解码数据库中的加密数据,以及密码等单向哈希数据 |
exposed-java-time | 基于 Java 8 Time API 的日期时间扩展 |
exposed-jodatime | 基于 Joda-Time 库的日期时间扩展 |
exposed-json | JSON 与 JSONB 数据类型扩展 |
exposed-kotlin-datetime | 基于kotlinx-datetime库的日期时间扩展 |
exposed-money | 支持 JavaMoney API 的MonetaryAmount类型扩展 |
exposed-spring-boot-starter | 面向 Spring Boot 3 的 starter,将 Exposed 用作 ORM |
exposed-spring-boot4-starter | 面向 Spring Boot 4 的 starter,将 Exposed 用作 ORM |
spring-transaction | 基于 Spring Framework 6 标准事务流程构建的事务管理器 |
spring7-transaction | 基于 Spring Framework 7 标准事务流程构建的事务管理器 |
exposed-migration-core | 数据库 schema 迁移的核心通用功能 |
exposed-migration-jdbc | 依赖 JDBC 驱动的数据库 schema 迁移工具 |
exposed-migration-r2dbc | 依赖 R2DBC 驱动的数据库 schema 迁移工具 |
这些扩展模块在仓库中均有对应目录,例如 exposed-json、exposed-java-time、exposed-money、exposed-migration-core 等,每个模块都自带api/*.api文件记录公开 API,供需要深度定制数据类型的读者继续查阅。
Groovy Gradle 中的最小依赖集
在Adding-dependencies.md的「Add dependencies」小节中,官方为 Groovy DSL 给出了最小可行依赖集——一个 Exposed 应用至少需要「核心模块 + 恰好一个传输模块」:
dependencies { implementation "org.jetbrains.exposed:exposed-core:%exposed_version%" implementation "org.jetbrains.exposed:exposed-jdbc:%exposed_version%" implementation "org.jetbrains.exposed:exposed-dao:%exposed_version%" //optional }逐行解读:
exposed-core:必选,DSL 与类型安全抽象的基础;exposed-jdbc:必选,传输层(若走响应式路线则替换为exposed-r2dbc);exposed-dao:可选,注释已标明//optional,只有需要 DAO 高层 API 时才引入。
%exposed_version%是文档中的版本占位符。在当前仓库中,实际版本号定义在根目录 gradle.properties 中:version=1.5.0,即本仓库对应的 Exposed 版本为1.5.0。在你的工程中应替换为实际使用的版本,例如:
dependencies { implementation "org.jetbrains.exposed:exposed-core:1.5.0" implementation "org.jetbrains.exposed:exposed-jdbc:1.5.0" implementation "org.jetbrains.exposed:exposed-dao:1.5.0" // 可选 }作为对照,同一主题文档中还提供了 Kotlin DSL 与 Maven 两种写法。Kotlin DSL 写法为:
dependencies { implementation("org.jetbrains.exposed:exposed-core:%exposed_version%") implementation("org.jetbrains.exposed:exposed-jdbc:%exposed_version%") implementation("org.jetbrains.exposed:exposed-dao:%exposed_version%") // Optional }Maven 写法为(pom.xml的dependencies段):
<dependencies> <dependency> <groupId>org.jetbrains.exposed</groupId> <artifactId>exposed-core</artifactId> <version>%exposed_version%</version> </dependency> <dependency> <groupId>org.jetbrains.exposed</groupId> <artifactId>exposed-jdbc</artifactId> <version>%exposed_version%</version> </dependency> <dependency> <groupId>org.jetbrains.exposed</groupId> <artifactId>exposed-dao</artifactId> <version>%exposed_version%</version> </dependency> </dependencies>三种构建系统的依赖坐标完全一致,差异仅在语法:Groovy 用implementation "group:artifact:version"(引号字符串),Kotlin DSL 用implementation("group:artifact:version"),Maven 用<artifactId>标签。
配置仓库源
在声明依赖之前,需要先确保构建能从 Maven Central 拉取 Exposed 构件。Adding-dependencies.md指出Exposed 模块发布在 Maven Central 仓库。Groovy DSL 的配置方式为:
repositories { mavenCentral() }对于 Maven 用户,Maven Central 默认启用,无需额外配置。Kotlin DSL 写法与 Groovy 相同(mavenCentral()方法在两种 DSL 中同名)。
使用版本目录(Version Catalog)统一管理 Exposed 版本
为了免去手写每个坐标和版本号的繁琐,Exposed 官方发布了exposed-version-catalog——一个专为所有已发布 Exposed 模块设计的 Gradle 版本目录。仓库中的 exposed-version-catalog/README.md 对其用法给出了完整说明。
在 settings 中导入目录
在settings.gradle.kts(或 Groovy 语法的settings.gradle)的dependencyResolutionManagement块中创建目录:
dependencyResolutionManagement { repositories { mavenCentral() } versionCatalogs { create("exposedLibs") { from("org.jetbrains.exposed:exposed-version-catalog:%exposed_version%") } } }通过类型安全访问器引用模块
导入后,即可在构建脚本中用类型安全访问器引用各模块,而无需硬编码坐标:
dependencies { implementation exposedLibs.core implementation exposedLibs.jdbc implementation exposedLibs.dao // Optional }访问器的命名规则是:去掉exposed-前缀,将其余部分按-拆分为嵌套访问器。例如:
| 模块 | 访问器 |
|---|---|
exposed-core | exposedLibs.core |
exposed-jdbc | exposedLibs.jdbc |
exposed-r2dbc | exposedLibs.r2dbc |
exposed-kotlin-datetime | exposedLibs.kotlin.datetime |
spring7-transaction | exposedLibs.spring7.transaction |
统一覆盖版本
由于所有模块共享同一个exposed版本,你可以在一处覆盖整个目录的 Exposed 版本:
versionCatalogs { create("exposedLibs") { from("org.jetbrains.exposed:exposed-version-catalog:%exposed_version%") version("exposed", "%exposed_version%") } }当前仓库的实际示例版本为1.5.0(参见 exposed-version-catalog/README.md 中的from("org.jetbrains.exposed:exposed-version-catalog:1.5.0")),替换占位符后即为:
versionCatalogs { create("exposedLibs") { from("org.jetbrains.exposed:exposed-version-catalog:1.5.0") version("exposed", "1.5.0") } }为什么叫exposedLibs而不是exposed?
这是一个非常容易踩坑的细节。官方文档与 exposed-version-catalog/README.md 均明确指出:
Exposed Gradle 插件会注册一个名为
exposed的项目扩展(即exposed { migrations { } }DSL)。而版本目录同样会以目录名作为项目扩展暴露出来,因此若将目录命名为exposed,会与插件扩展冲突(报错Cannot add extension with name 'exposed')。命名为exposedLibs可让两者在同一工程中共存。如果你不应用 Exposed Gradle 插件,则可以自由地将目录命名为exposed,并使用exposed.core这类访问器。
此外还有两点补充约束:
- 版本目录是 Gradle 特性,Maven 用户无法使用,应如前文所示直接声明依赖坐标;
- 若同时使用 Exposed Gradle 插件(exposed-gradle-plugin),务必保留
exposedLibs命名以避免冲突。
补充 JDBC/R2DBC 驱动依赖
Exposed 本身不包含任何数据库驱动,你需要为所使用的数据库额外引入对应的 JDBC 或 R2DBC 驱动。以 H2 数据库为例,Groovy DSL 写法为:
dependencies { implementation "com.h2database:h2:%h2_db_version%" }Kotlin DSL 写法为:
dependencies { implementation("com.h2database:h2:%h2_db_version%") }Maven 写法为:
<dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.4.240</version> </dependency> </dependencies>官方文档提示:受支持数据库及其对应驱动依赖的完整列表,参见 Working with Database。
在仓库中,exposed-tests与exposed-jdbc等模块的实际测试配置使用了 H2 等数据库驱动进行集成验证(见各模块build.gradle.kts中的 test 依赖),这也印证了「驱动必须独立引入」的约定。
补充日志依赖:让 SQL 日志可见
Exposed 的StdOutSqlLogger通过 SLF4J 输出 SQL 日志,因此你需要一个 SLF4J 绑定实现,否则可能遇到StaticLoggerBinder相关告警且看不到日志。官方给出了两种选择:
最小方案(无输出)——使用slf4j-nop,静默丢弃日志:
dependencies { // Minimal logging (no output) implementation "org.slf4j:slf4j-nop:%slf4j_version%" }完整方案——使用 Logback 获得全功能日志输出:
dependencies { // Full-featured logging using Logback implementation "ch.qos.logback:logback-classic:%logback_version%" }关于为何需要日志依赖的详细解释,官方文档指向了 SLF4J 官方文档的
StaticLoggerBinder错误说明:当 classpath 中没有任何 SLF4J 绑定实现时,SLF4J 会报告Failed to load class "org.slf4j.impl.StaticLoggerBinder",此时日志将退化为无输出。
仓库源码同样印证了这一依赖关系:exposed-core中定义了 StdOutSqlLogger(对应 API 文档org.jetbrains.exposed.v1.core.StdOutSqlLogger),其实现基于 SLF4J 的LoggerFactory输出 SQL 语句。因此在实际项目中,若希望看到 Exposed 生成的 SQL,logback-classic(或slf4j-simple等其他绑定)是必备项。
常见问题与最佳实践小结
围绕该 Groovy 示例工程与官方依赖指南,汇总如下实践要点:
- 最小依赖恒等式:
exposed-core+ 恰好一个传输模块(exposed-jdbc或exposed-r2dbc)即可运行;exposed-dao按需引入,且仅兼容 JDBC 传输层。 - 传输层二选一:不要同时引入
exposed-jdbc与exposed-r2dbc,两者互斥。 - 驱动必须自备:Exposed 不捆绑任何数据库驱动,H2、MySQL、PostgreSQL 等驱动的坐标需要自己声明。
- 日志绑定不能少:想看到 SQL 日志,必须在 classpath 中放置至少一个 SLF4J 绑定(推荐
logback-classic)。 - 版本目录推荐使用:通过
org.jetbrains.exposed:exposed-version-catalog导入类型安全访问器,并在settings中统一管理版本;注意目录命名为exposedLibs以避免与 Exposed Gradle 插件的exposed扩展冲突。 - Groovy 与 Kotlin DSL 语法差异:Groovy 使用
implementation "group:artifact:version"与implementation exposedLibs.core,Kotlin DSL 使用implementation("...")与implementation(exposedLibs.core),其余语义完全一致。 - 版本号对齐:当前仓库对应的 Exposed 版本为 1.5.0(见 gradle.properties),所有模块应使用同一版本。
通过本文的配置,你的 Groovy Gradle 工程即可获得一套完整、可运行、便于后续扩展的 Exposed 依赖体系。若需深入学习 DSL 与 DAO 的用法,仓库中对应的可运行示例(如 exposed-dsl、exposed-dao)是下一步的最佳入口。
- ORM
- 后端
- 数据存储
【免费下载链接】Exposed
Kotlin SQL Framework
相关推荐
Kubo 在 Windows 上从源码构建:MSYS2、Cygwin 与 Minimal 三种方案完整指南
Kubo 在 Windows 上从源码构建:MSYS2、Cygwin 与 Minimal 三种方案完整指南 本篇技术指南以 docs/windows.md ht
ORM后端数据存储Exposed 1.0 迁移之构建文件改造:Gradle KTS / Groovy / Version Catalog / Maven 全模式指南
Exposed 1.0 迁移之构建文件改造:Gradle KTS / Groovy / Version Catalog / Maven 全模式指南 Expose
ORM后端数据存储Android Topeka Gradle配置终极指南:多模块构建与依赖管理完整教程
Android Topeka Gradle配置终极指南:多模块构建与依赖管理完整教程 Topeka是一个展示Android Material Design的趣味
移动开发示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考