Slick:如何巧妙地关闭资源和链式操作
Slick: How to neatly close resources and chain actions
我今天写了一个精巧的小程序。有用。这是代码
package com.abhi
import slick.driver.MySQLDriver.api._
import slick.jdbc.meta.MTable
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
object MySlickApp extends App {
val db = Database.forConfig("essential-slick ")
val messages = TableQuery[MessageTable]
val tableExists = MTable.getTables map { tables =>
tables.exists(_.name.name == messages.baseTableRow.tableName)
}
val dropAction = messages.schema.drop
val createAction = messages.schema.create
val freshMessages = Seq(
Message("Dave", "Hello HAL. Do you read me? HAL?"),
Message("HAL", "Affirmtive, Dave. I read you."),
Message("Dave", "Open the pod doors, HAL."),
Message("HAL", "I'm Sorry. Dave. I'm afraid, I cannot do that.")
)
val insertAction = messages ++= freshMessages
val f5 = for {
f1 <- db.run(tableExists)
f2 <- db.run(dropAction) if f1 == true
f3 <- db.run(createAction)
f4 <- db.run(insertAction)
} yield (f1, f2, f3, f4)
f5.onComplete{
case Success(s) => println("table initialized successfully "); db.close
case Failure(f) => println(f.getMessage); db.close
}
scala.io.StdIn.readLine()
}
final case class Message (sender: String, content: String, id: Long = 0L)
final case class MessageTable(tag: Tag) extends Table[Message](tag, "Message") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def sender = column[String]("sender")
def content = column[String]("content")
def * = (sender, content, id) <> (Message.tupled, Message.unapply)
}
这个程序有两点我不喜欢
我必须在理解的每一行上指定 db.run。我试图将我所有的操作放在一个 Seq 中,然后将 DBIO.seq 提供给 db.run 但它 运行 一切都是异步的而不是有序的。
我必须在 "success" 和 "failure" 两种情况下调用 db.close。我想知道是否有一种方法可以在一个地方不重复地关闭资源。
使用最新的 slick 3.2
1. 您可以通过将 DBIOActions 链接在一起而不是 futures 运行 它作为单个数据库 运行 这种方式。这样做还提供了 运行 将其作为事务处理的额外好处:
val f = for {
r1 <- tableExists
r2 <- {
if(r1){
dropAction
}else{
DBIO.successful()
}
}
r3 <- createAction
r4 <- insertAction
} yield (f)
db.run(f).transactionally
- calling db.close: 确实没有必要调用db close。这不会关闭连接。这样做会关闭整个数据库设置/连接池等)。没有手动关闭连接的机制,因为 slick 已经在 db.run 调用中为您处理了这个问题。
由于这是一个 "run once" 程序,因此无论哪种方式都无关紧要。如果这是 运行ning 作为 Web 服务类型的程序,任何对该服务的后续请求将永远无法再次连接到数据库!
我今天写了一个精巧的小程序。有用。这是代码
package com.abhi
import slick.driver.MySQLDriver.api._
import slick.jdbc.meta.MTable
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
object MySlickApp extends App {
val db = Database.forConfig("essential-slick ")
val messages = TableQuery[MessageTable]
val tableExists = MTable.getTables map { tables =>
tables.exists(_.name.name == messages.baseTableRow.tableName)
}
val dropAction = messages.schema.drop
val createAction = messages.schema.create
val freshMessages = Seq(
Message("Dave", "Hello HAL. Do you read me? HAL?"),
Message("HAL", "Affirmtive, Dave. I read you."),
Message("Dave", "Open the pod doors, HAL."),
Message("HAL", "I'm Sorry. Dave. I'm afraid, I cannot do that.")
)
val insertAction = messages ++= freshMessages
val f5 = for {
f1 <- db.run(tableExists)
f2 <- db.run(dropAction) if f1 == true
f3 <- db.run(createAction)
f4 <- db.run(insertAction)
} yield (f1, f2, f3, f4)
f5.onComplete{
case Success(s) => println("table initialized successfully "); db.close
case Failure(f) => println(f.getMessage); db.close
}
scala.io.StdIn.readLine()
}
final case class Message (sender: String, content: String, id: Long = 0L)
final case class MessageTable(tag: Tag) extends Table[Message](tag, "Message") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def sender = column[String]("sender")
def content = column[String]("content")
def * = (sender, content, id) <> (Message.tupled, Message.unapply)
}
这个程序有两点我不喜欢
我必须在理解的每一行上指定 db.run。我试图将我所有的操作放在一个 Seq 中,然后将 DBIO.seq 提供给 db.run 但它 运行 一切都是异步的而不是有序的。
我必须在 "success" 和 "failure" 两种情况下调用 db.close。我想知道是否有一种方法可以在一个地方不重复地关闭资源。
使用最新的 slick 3.2 1. 您可以通过将 DBIOActions 链接在一起而不是 futures 运行 它作为单个数据库 运行 这种方式。这样做还提供了 运行 将其作为事务处理的额外好处:
val f = for {
r1 <- tableExists
r2 <- {
if(r1){
dropAction
}else{
DBIO.successful()
}
}
r3 <- createAction
r4 <- insertAction
} yield (f)
db.run(f).transactionally
- calling db.close: 确实没有必要调用db close。这不会关闭连接。这样做会关闭整个数据库设置/连接池等)。没有手动关闭连接的机制,因为 slick 已经在 db.run 调用中为您处理了这个问题。 由于这是一个 "run once" 程序,因此无论哪种方式都无关紧要。如果这是 运行ning 作为 Web 服务类型的程序,任何对该服务的后续请求将永远无法再次连接到数据库!