AFAIK Slick访问数据库的方式是创建session
的隐式实例(每个应用程序一个),然后
通过implicit
参数将其传递到应用程序中的任何地方,会话将通过以下方式访问数据库
值db
,我们可以使用session.db.run运行查询。
对我来说,问题是我如何知道滑动实际实例化了多少个连接(真实连接而不是概念连接)?
我之所以问这个问题,是因为我有SQLite的异常:
java.sql.SQLException: [SQLITE_BUSY] The database file is locked (database is locked)
at org.sqlite.DB.newSQLException(DB.java:383)
at org.sqlite.DB.newSQLException(DB.java:387)
at org.sqlite.DB.throwex(DB.java:374)
at org.sqlite.NativeDB.prepare(Native Method)
at org.sqlite.DB.prepare(DB.java:123)
at org.sqlite.PrepStmt.<init>(PrepStmt.java:42)
at org.sqlite.Conn.prepareStatement(Conn.java:404)
at org.sqlite.Conn.prepareStatement(Conn.java:399)
at org.sqlite.Conn.prepareStatement(Conn.java:383)
at slick.jdbc.JdbcBackend$SessionDef.prepareStatement(JdbcBackend.scala:321)
at slick.jdbc.JdbcBackend$SessionDef.prepareStatement$(JdbcBackend.scala:311)
at slick.jdbc.JdbcBackend$BaseSession.prepareStatement(JdbcBackend.scala:433)
at slick.jdbc.StatementInvoker.results(StatementInvoker.scala:32)
at slick.jdbc.StatementInvoker.iteratorTo(StatementInvoker.scala:21)
at slick.jdbc.Invoker.foreach(Invoker.scala:47)
at slick.jdbc.Invoker.foreach$(Invoker.scala:46)
at slick.jdbc.StatementInvoker.foreach(StatementInvoker.scala:15)
at slick.jdbc.StreamingInvokerAction.run(StreamingInvokerAction.scala:22)
at slick.jdbc.StreamingInvokerAction.run$(StreamingInvokerAction.scala:20)
at slick.jdbc.SQLActionBuilder$$anon$1.run(StaticQuery.scala:95)
at slick.jdbc.SQLActionBuilder$$anon$1.run(StaticQuery.scala:95)
at slick.basic.BasicBackend$DatabaseDef$$anon$2.liftedTree1$1(BasicBackend.scala:242)
at slick.basic.BasicBackend$DatabaseDef$$anon$2.run(BasicBackend.scala:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
那是因为SQLite不允许并发访问 如何防止Slick同时访问我的SQLite数据库?
我正在做的是以下事情:
我有一个连接到actor接收器的Akka流,该接收器使用隐式提供的会话来运行少量查询 (一个插入和四个选择)使用下面的for comprehension来说明我要解释的伪代码
val dbConnector = system.actorOf(DBConnector.props)
val sinkDBConnetor = Sink.actorRefWithAck(dbConnector, "init", "ack", "complete", println)
val sqlSink = Flow[TDM[Instant, BucketedStats[Stats.SimpleStats]]]
.map(e => UpdateTypicalHR(e.key.get.toLong, e.when.get.from.getEpochSecond(), e.value.stats.max))
.to(sinkDBConnetor)
class DBConnector extends Actor with ActorLogging {
override def receive: Receive = {
case UpdateTypicalHR(watch_id: Long, timestamp: Long, value: Double) =>
val request =
(for {
_ <- insertHr(watch_id, timestamp, value)
t <- typicalHr(watch_id, timestamp)
a1 <- checkDailyVariation(watch_id, timestamp)
a2 <- check8HoursVariation(watch_id, timestamp)
a3 <- checkHourlyVariation(watch_id, timestamp)
} yield (t, a1 ++ a2 ++ a3)).transactionally
session.db.run(request).onComplete {
case Success((typical, alerts)) =>
log.debug("Read Intic")
sender() ! "database is free"
case Failure(exception) =>
session.close()
sender() ! "database is free"
}
}
}