Haskell 中的并发数据库连接池
我是一名学习 Haskell 的 Java 程序员。
我正在开发一个小型 Web 应用程序,该应用程序使用 Happstack 并通过 HDBC 与数据库进行通信。
我编写了 select 和 exec 函数,并且像这样使用它们:
module Main where
import Control.Exception (throw)
import Database.HDBC
import Database.HDBC.Sqlite3 -- just for this example, I use MySQL in production
main = do
exec "CREATE TABLE IF NOT EXISTS users (name VARCHAR(80) NOT NULL)" []
exec "INSERT INTO users VALUES ('John')" []
exec "INSERT INTO users VALUES ('Rick')" []
rows <- select "SELECT name FROM users" []
let toS x = (fromSql x)::String
let names = map (toS . head) rows
print names
如您所见,非常简单。 有查询、参数和结果。
连接创建和提交/回滚内容隐藏在 select 和 exec 中。
这很好,我不想在我的“逻辑”代码中关心它。
exec :: String -> [SqlValue] -> IO Integer
exec query params = withDb $ \c -> run c query params
select :: String -> [SqlValue] -> IO [[SqlValue]]
select query params = withDb $ \c -> quickQuery' c query params
withDb :: (Connection -> IO a) -> IO a
withDb f = do
conn <- handleSqlError $ connectSqlite3 "users.db"
catchSql
(do r <- f conn
commit conn
disconnect conn
return r)
(\e@(SqlError _ _ m) -> do
rollback conn
disconnect conn
throw e)
缺点:
- 每次调用都会创建一个新连接 - 这会降低重负载时的性能
- DB url“users.db”是硬编码的 - 我无法在其他项目中重用这些函数而无需编辑
问题1:如何引入一个具有一些定义的(最小,最大)并发连接数的连接池,以便在 select/exec 调用之间重用连接?
问题2:如何使“users.db”字符串可配置? (如何将其移至客户端代码?)
它应该是一个透明的功能:用户代码不应要求显式的连接处理/释放。
I am a Java programmer who learns Haskell.
I work on a small web-app that uses Happstack and talks to a database via HDBC.
I've written select and exec functions and I use them like this:
module Main where
import Control.Exception (throw)
import Database.HDBC
import Database.HDBC.Sqlite3 -- just for this example, I use MySQL in production
main = do
exec "CREATE TABLE IF NOT EXISTS users (name VARCHAR(80) NOT NULL)" []
exec "INSERT INTO users VALUES ('John')" []
exec "INSERT INTO users VALUES ('Rick')" []
rows <- select "SELECT name FROM users" []
let toS x = (fromSql x)::String
let names = map (toS . head) rows
print names
Very simple as you see. There is query, params and result.
Connection creation and commit/rollback stuff is hidden inside select and exec.
This is good, I don't want to care about it in my "logic" code.
exec :: String -> [SqlValue] -> IO Integer
exec query params = withDb $ \c -> run c query params
select :: String -> [SqlValue] -> IO [[SqlValue]]
select query params = withDb $ \c -> quickQuery' c query params
withDb :: (Connection -> IO a) -> IO a
withDb f = do
conn <- handleSqlError $ connectSqlite3 "users.db"
catchSql
(do r <- f conn
commit conn
disconnect conn
return r)
(\e@(SqlError _ _ m) -> do
rollback conn
disconnect conn
throw e)
Bad points:
- a new connection is always created for every call - this kills performance on heavy load
- DB url "users.db" is hardcoded - I can't reuse these functions across other projects w/o editing
QUESTION 1: how to introduce a pool of connections with some defined (min, max) number of concurrent connections, so the connections will be reused between select/exec calls?
QUESTION 2: How to make "users.db" string configurable? (How to move it to client code?)
It should be a transparent feature: user code should not require explicit connection handling/release.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
resource-pool 包提供了一个高性能的资源池,可用于数据库连接池。 例如:
创建一个数据库连接池,有1个子池,最多5个连接。 每个连接在被销毁之前允许空闲 10 秒。
The resource-pool package provides a high-performance resource pool which can be used for database connection pooling. For example:
Creates a database connection pool with 1 sub-pool and up to 5 connections. Each connection is allowed to be idle for 10 seconds before being destroyed.
问题 2:我从未使用过 HDBC,但我可能会写这样的东西。
在函数外部的某个位置打开
Connection
,并且不要在函数内断开连接。问题 1: 嗯,连接池似乎并不难实现...
您可能不应该逐字逐句地接受这个,因为我什至还没有对它进行编译测试(并且
失败
这相当不友好),但我们的想法是做一些类似的事情,并根据需要传递
connPool
。QUESTION 2: I've never used HDBC, but I'd probably write something like this.
Open the
Connection
somewhere outside of the function, and don't disconnect it within the function.QUESTION 1: Hmm, a connection pool doesn't seem that hard to implement...
You probably shouldn't take this verbatim as I haven't even compile-tested it (and
fail
there is pretty unfriendly), but the idea is to do something likeand pass
connPool
around as needed.我修改了上面的代码,现在至少可以编译了。
I modified the code above, now it's able to compile at least.