-
-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataBase 和Query解耦 #41
Comments
这是可以的,看看这段代码是不是你想要的效果? val db = Database.connect(url = "jdbc:h2:mem:ktorm;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
val names = db {
Employees
.select(Employees.name)
.where { Employees.departmentId eq 1 }
.orderBy(Employees.salary.desc())
.map { it.getString(1) }
}
assert(names.size == 2)
assert(names[0] == "vince")
assert(names[1] == "marry") |
嗯,我看到了,可以这样写。但是这个db是通过threadlocal的方式传递给map的。如果不用这个db{}包裹代码块,容易有坑(代码也不会提示不可以不包裹),比如在多线程执行的时候。 另外,把query定义为一个SQL构造器,而不直接map执行。用类似这样的方式进行绑定,个人认为代码风格更好些。 db.from(Employees)
.where { e -> (e.organizationId ne null) and (e.name eq "John Doe") }
.groupBy { e -> e.name }
.having { e -> e.id ne null }
.orderBy { e -> e.name.asc .. e.id.desc }
.limit { 10 }
.offset { 10 }
.select { e -> e.id .. e.name } 或者类似slick这样: val setup = DBIO.seq(
// Create the tables, including primary and foreign keys
(suppliers.schema ++ coffees.schema).create,
// Insert some suppliers
suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199"),
suppliers += ( 49, "Superior Coffee", "1 Party Place", "Mendocino", "CA", "95460"),
suppliers += (150, "The High Ground", "100 Coffee Lane", "Meadows", "CA", "93966"),
// Equivalent SQL code:
// insert into SUPPLIERS(SUP_ID, SUP_NAME, STREET, CITY, STATE, ZIP) values (?,?,?,?,?,?)
// Insert some coffees (using JDBC's batch insert feature, if supported by the DB)
coffees ++= Seq(
("Colombian", 101, 7.99, 0, 0),
("French_Roast", 49, 8.99, 0, 0),
("Espresso", 150, 9.99, 0, 0),
("Colombian_Decaf", 101, 8.99, 0, 0),
("French_Roast_Decaf", 49, 9.99, 0, 0)
)
// Equivalent SQL code:
// insert into COFFEES(COF_NAME, SUP_ID, PRICE, SALES, TOTAL) values (?,?,?,?,?)
)
val setupFuture = db.run(setup)
前3步都是和执行环境无关的,抽离之后,后续切换到coroutine 执行,只需要改进第4部分。 |
谢谢你的建议,把 query 表达式的构造与执行环境分离确实有很大的意义,我会考虑如何改进 |
我们刚开始在服务端使用kotlin,评估下来,ktorm是orm这块做的比较好的,也感谢你对项目的付出。 |
@jiaojing 我也在尝试用coroutine来执行sql, 但是感觉需要用异步的DB调用,而不是JDBC这种会阻塞线程的才有效,要不然也只是相当于在一个线程池里面做DB调用(这样同时的并发数,就是线程池数量与数据库连接池数量的两者最小值),我找到了这个数据库driver, |
是这样的,异步和同步是两个完全不一样的世界,很多库都没办法做到完美地同时支持两者。 我的想法是,与 所以,与其这么做,我觉得还不如另外建一个 ktorm-async 的项目,一个支持异步的专门的 Ktorm 版本。反正代码都要重新写一遍,我不如直接把同步的 Ktorm 和异步的 Ktorm 分为两个项目,它们之间顶多就共享 你看看这个思路如何? |
嗯,也是一种方案。核心的就是SqlExpresion。然后DB执行他。 我去看了一下slick的方式。他是把query的拼接,数据库的其他操作,都和执行环境全部分离出来。 然后DB.run(DBIOAction)-> future 这种方式把所有最终的执行几乎都放到这一个函数里去了。这个函数返回的是future,也就是底层是同步(那就得自己用线程池转成异步的)或者异步的驱动都可以。所有的terminal 函数,最终调用这个run得到一个future。然后future就可以很简单转成suspend了。 不过这个我感觉不着急,kotlin目前还不成熟。我估计得等1.4以后,看看哪个版本kotlin的 multi-platform做好以后,coroutine的使用场景才会出来吧。目前也就Android下能用。服务端基本上都是spring的生态,基本用不到。 |
最近翻了一下代码,其实query本身的构造,是不会suspend的。就是一个普通的函数。database.run(query)这个涉及到网络io,肯定是suspend的。之后获得一个QueryResult,然后再这个之后所有的数据结果的处理,变换按照我的理解,也是一个普通函数,不会suspend。也就是说整个coroutine控制在db的run方法上。这个database根据底层driver情况,提供两套执行的api其实就是suspend runAsync(query),runSync(query).然后使用者自行选择就行。 `kotlin public suspend fun Query.runBy(database: Database): QueryResult = QueryResult(database, this) ` |
query,最后map的时候会调用global的DataBase执行。是否可以类似:slick
// DB.run(DBIOActions) 这种方式。
项目非常棒,💪
The text was updated successfully, but these errors were encountered: