根据其官方文档,SQLDelight库以从SQL语句生成类型安全的Kotlin APIs而闻名。凭借其模式验证、语句和编译时迁移,SQLDelignt提供了IDE功能,使编写和维护SQL变得简单。
那么,SQLDelight做了什么其他库没有的事情呢?让我们以最著名的本地Android开发库Room为例。
这两个库都围绕着SQLite数据库,它通过提供Kotlin和Java API来推理大多数带有编译时验证的CRUD操作,从而避免了我们使用噩梦般的SQLiteOpenHelper 。
SQLDelight的与众不同之处在于,除了Android之外,它还支持跨平台,可以选择将底层数据库改为MySQL 、Postgress 、或HSQL/H2 。
使用Kotlin多平台移动,SQLDelight还提供了跨平台的兼容性,有平台无关的API,可以在Android、iOS等不同平台上分享业务逻辑代码。
而且,SQLDelight提供了语法高亮和自动完成、迁移测试和导出、为Java虚拟机(JVM)项目切换底层数据库的能力,并支持coroutines和RxJava。
在这篇文章中,我们将介绍以下内容。
好了,让我们开始吧!
设置SQLDelight
由于JVM项目对于iOS或Android开发者来说是最具有平台中立性的,这里提到的所有操作都适用于本地移动开发。唯一的变化将是加入的数据库驱动的依赖性。
首先,打开IntelliJ ,在其中创建一个新项目。然后,选择Kotlin,并将以下依赖项添加到Console Application 。
buildscript {
repositories {
google()
mavenCentral()
maven { url "https://www.jetbrains.com/intellij-repository/releases" }
maven { url "https://jetbrains.bintray.com/intellij-third-party-dependencies" }
}
dependencies {
classpath 'com.squareup.sqldelight:gradle-plugin:1.5.0'
}
}
apply plugin: 'com.squareup.sqldelight'
dependencies {
implementation 'com.squareup.sqldelight:jdbc-driver:1.5.1'
implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'org.slf4j:slf4j-simple:1.7.32'
implementation 'mysql:mysql-connector-java:8.0.26'
testImplementation 'org.jetbrains.kotlin:kotlin-test:1.5.31'
}
sqldelight {
Database { // This will be the name of the generated database class.
packageName = "com.example"
dialect = "mysql"
}
}
设置MySQL数据库
现在我们已经为SQLDelight设置好了一切,让我们继续设置一个MySQL数据库。
首先,为你的设备下载并安装MySQL(macOS请按这里)。
然后,你可以安装一个可视化工具来可视化数据,如TablePlus或Workbench,并将你的数据库连接到可视化工具,这样我们就可以看到实时的数据变化。
创建一个名为movies_db 的数据库;你可以通过将 这个csv作为一个新的表导入我们的movies_db database ,来导入一个样本数据集用于本教程。
我们的db ,然后看起来像这样。
将SQLDelight连接到MySQL数据库
现在,让我们回到我们的Java项目!
为了让SQLDelight连接到MySQL数据库,它需要一个DataSource ,我们可以从像HikariCP这样的连接管理器中获得这个实例。
然后,我们可以创建下面的函数,将Datasource 到Main.kt 文件中。
private fun getSqlDriver(): SqlDriver {
val ds = HikariDataSource()
ds.jdbcUrl = "jdbc:mysql://localhost:3306/movies_db"
ds.driverClassName = "com.mysql.jdbc.Driver"
ds.username = "root"
ds.password = "mysqlroot"
return ds.asJdbcDriver()
}
接下来,让我们在src/sqldelight 目录下创建一个Movie.sq 文件,并添加一个SELECT 语句。
CREATE TABLE movies (
Film text,
Genre text,
`Lead Studio` text,
`Audience score` int DEFAULT NULL,
Profitability float DEFAULT NULL,
`Rotten Tomatoes` int DEFAULT NULL,
`Worldwide Gross` text,
Year int DEFAULT NULL
);
selectAll:
SELECT *
FROM movies;
随着我们项目的构建,SQLDelight会创建所需的模型和查询文件。这可以帮助我们以后进行调试和测试。
为了测试我们的初始代码,我们可以在我们的main 函数中写下以下内容并运行。
fun main(args: Array<String>) {
val database = Database(getSqlDriver())
val moviesQueries = database.movieQueries
val movies = moviesQueries.selectAll().executeAsList()
println(movies)
}
这将在终端打印出我们的Movies 表。
注意,在生产中,我们应该只初始化一次数据库代码,并将其作为单子重用,以防止内存问题。
在SQLDelight中的CRUD操作
所有基本的CRUD操作仍然与在.sq 文件中写一个SQL查询前缀的方法名称一样,SQLDelight会建立所需的函数和数据模型。
Insert
正如我们从SQLDelight构建文件中看到的那样,我们有一个从数据库中的电影表创建的Movies 数据类。
我们有两个选择来进行插入:用movies 表中的每个值创建一个函数,或者传递整个movie 对象。
如果我们按值创建一个函数,我们有如下的结果。
insert:
INSERT INTO movies(Film, Genre, `Lead Studio`, `Worldwide Gross`, Year)
VALUES(?, ?, ?, ?,?);
如果我们按对象创建一个函数,我们就有以下结果。
insertObject:
INSERT INTO movies(Film, Genre, `Lead Studio`, `Audience score`, Profitability,
`Rotten Tomatoes`, `Worldwide Gross`, Year)
VALUES ?;
现在,我们可以在我们的main 函数中建立和运行这些方法。
fun main(args: Array<String>) {
....
// Insert by values
insert(
"Deadpool",
"Action/Adventure",
"20th Century Fox",
"$734",
2016
)
// Insert object
val movie = Movies(
Film = "Wonder Woman",
Genre = "Action/Adventure",
Lead_Studio = "DC Films",
Audience_score = null,
Profitability = null,
Rotten_Tomatoes = null,
Worldwide_Gross = "$66",
Year = 2017
)
insert(movie)
}
private fun insert(
film: String,
genre: String,
leadStudio: String,
worldwideGross: String,
year: Int
) {
moviesQueries.insert(film, genre, leadStudio, worldwideGross, year)
}
private fun insert(movies: Movies) {
moviesQueries.insertObject(movies)
}
通过打印或在查看器中查看我们的表格,我们可以验证以下数值。
Update
这里没有什么花哨的东西,只是通常的Update 查询,使我们能够更新我们数据库中的任何现有字段。
update:
UPDATE movies
SET `Worldwide Gross`=? WHERE Film=?;
然后它在Kotlin中构建了以下内容。
private fun update(worldwideGross: String, film: String) {
moviesQueries.update(worldwideGross, film)
}
Delete
继续我们的查询,我们可以添加delete 查询。
delete:
DELETE FROM movies WHERE Film=?;
然后在Kotlin中建立这个。
private fun delete(film: String) {
moviesQueries.delete(film)
}
Select
我们已经在上面看到了简单的选择查询,同时打印表格,所以让我们看看带有named 和variable 参数的Select 查询。
为了给Select 查询添加命名参数,我们必须添加以下内容。
filmOrGenre:
SELECT * FROM movies
WHERE Film LIKE :searchQuery
OR Genre LIKE :searchQuery;
然后在Kotlin中建立以下内容。
private fun searchFilmOrGenre(query: String): List<Movies> {
return moviesQueries.filmOrGenre(searchQuery = query).executeAsList()
}
在这里,我们可以传递一组值作为参数,以便在我们的应用程序中启用搜索功能。
filmByNames:
SELECT * FROM movies
WHERE Film IN ?;
然后在Kotlin中构建。
private fun searchFilmsByName(films: List<String>): List<Movies> {
return moviesQueries.filmByNames(films).executeAsList()
}
最后,在main 函数中,我们可以传递一个要搜索的电影列表。
searchFilmsByName(listOf("Penelope", "Valentine's Day", "Mamma Mia!"))
交易
我们还可以使用transaction 函数在一个事务中执行多个语句,并可以选择回调或回滚。
当我们有许多必须合并的查询时,这很有帮助,因为单独运行多个查询会导致内存开销。
因此,让我们在一个函数中插入多个电影,如下所示。
val bunchOfMovies = listOf(
Movies(
Film = "Sunny",
Genre = "",
Lead_Studio = "Dreams N Beyond",
Audience_score = null,
Profitability = null,
Rotten_Tomatoes = null,
Worldwide_Gross = "",
Year = 2021
),
Movies(
Film = "Kala",
Genre = "Crime",
Lead_Studio = "Juvis Productions",
Audience_score = null,
Profitability = null,
Rotten_Tomatoes = null,
Worldwide_Gross = "",
Year = 2020
),
)
moviesQueries.transaction {
bunchOfMovies.forEach { movie ->
moviesQueries.insertObject(movie)
}
}
现在,假设我们需要在运行时根据某些条件取消整个事务;我们可以选择使用rollback() ,进行回滚。
moviesQueries.transaction {
bunchOfMovies.forEach { movie ->
if (movie.Genre.isNullOrEmpty())
rollback()
moviesQueries.insertObject(movie)
}
}
我们还可以选择在我们的任何要求没有得到满足的情况下,获得交易完成或回滚的回调。
// Rollback
moviesQueries.transaction {
afterCommit {
println(
"Transaction complete: ${bunchOfMovies.size} movies inserted"
)
}
afterRollback { println("Rollback: No movies were inserted") }
bunchOfMovies.forEach { movie ->
if (movie.Genre.isNullOrEmpty())
rollback()
moviesQueries.insertObject(movie)
}
}
结论
就这样,我们已经涵盖了使用SQLDelight进行类型安全的Kotlin-esque数据库操作的基本知识。从这里开始,你可以深入研究一些高级操作,如迁移、快速文本搜索、自定义适配器等等。
完整的工作程序可以在这个Github Repo中找到。
SQLDelight介绍》一文首次出现在LogRocket博客上。