嘿,我读了这个jdbc文档 https://www.playframework.com/documentation/2.1.0/ScalaDatabase 这个问题 Is it good to put jdbc operations in actors?
现在我的mysql事务有一个ActorClass,每当请求到来时,这个actor都会多次实例化。所以每个请求都会实例化新的actor。连接池安全吗?
我可以使用
吗?val connection = DB.getConnection()
是连接对象可以处理异步事务吗? 所以我可以只用一个单例来处理mysql连接并在所有实例化的actor中使用它。另外,如果我想使用anorm,我该如何创建一个隐式连接对象?
由于
答案 0 :(得分:3)
如果您不想屏蔽演员,则DB.getConnection()
应为promise[Connection]
或future[Connection]
。 (答案结尾处的警告)
如果DB.getConnection()
是同步的(仅返回没有换行类型的连接),则actor将挂起,直到它在处理实际消息时实际从池中获取连接。无论您的数据库是单身还是无关,最终它都会触及连接池。
话虽这么说,你可以创建actor来处理消息传递和其他actor来处理数据库中的持久性,将它们放在不同的线程调度程序中,从而为数据库密集提供更多的线程。这也在PlayFramework中提出。
注意事项:
如果你在演员内部运行期货,你不确定它将运行的线程/时间,我假设你做了一些事情(阅读评论)
def receive = {
case aMessage =>
val aFuture = future(db.getConnection)
aFuture.map { theConn => //from previous line when you acquire the conn and when you execute the next line
//it could pass a long time they run in different threads/time
//that's why you should better create an actor that handles this sync and let
//akka do the async part
theConn.prepareStatemnt(someSQL)
//omitted code...
}
}
所以我的建议是
//actor A receives,
//actor B proccess db (and have multiple instances of this one due to slowness from db)
class ActorA(routerOfB : ActorRef) extends Actor {
def recieve = {
case aMessage =>
routerOfB ! aMessage
}
}
class ActorB(db : DB) extends Actor {
def receive = {
case receive = {
val conn = db.getConnection //this blocks but we have multiple instances
//and enforces to run in same thread
val ps = conn.prepareStatement(someSQL)
}
}
}
答案 1 :(得分:1)
据我所知,你无法在单个连接上为RDBMS运行多个并发查询(即使在C-API中,我还没有看到任何用于mysql的异步/非阻塞调用的资源/引用;)。要同时运行查询,您大多数都有多个连接实例。
DB.getConnection
并不昂贵。使用DB的最昂贵的区域是运行SQL查询并等待其响应。
要与您的数据库调用异步,您应该在其他线程中运行它们(不在Akka或Play的主线程池中);光滑为你做。它管理一个线程池并对它们运行数据库调用,然后你的主线程将可以自由处理收入请求。然后你不需要将演员中的DB调用包装成异步。
答案 2 :(得分:0)
我认为您应该从池中获取连接并在完成后返回。如果我们通过每个actor的单个连接,如果该连接断开连接,您可能需要重新初始化它。
对于您可能想要尝试的交易
DB.withTransaction { conn => // do whatever you need with the connection}
答案 3 :(得分:0)