Je suis un programmeur Java qui apprend Haskell.
Je travaille sur une petite application web qui utilise Happstack et qui parle à une base de données via HDBC.Pool de connexion DB simultané dans Haskell
J'ai écrit sélectionnez et exec fonctions et je les utilise comme ceci:
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
Très simple que vous voyez. Il y a requête, paramètres et résultat.
La création de la connexion et la validation/restauration sont masquées dans select et exec.
C'est bien, je ne veux pas m'en soucier dans mon code "logique".
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)
(\[email protected](SqlError _ _ m) -> do
rollback conn
disconnect conn
throw e)
Mauvais points:
- une nouvelle connexion est toujours créée pour chaque appel - cela tue les performances de la charge lourde
- DB url "users.db" est codé en dur - je ne peux pas réutiliser ces fonctions à travers d'autres projets w/o édition
QUESTION 1: comment introduire un pool de connexions wi un certain nombre défini (min, max) de connexions simultanées, de sorte que les connexions seront réutilisées entre les appels select/exec?
QUESTION 2: Comment rendre la chaîne "users.db" configurable? (Comment le déplacer vers le code client?)
Cela devrait être une fonctionnalité transparente: le code utilisateur ne devrait pas nécessiter de manipulation/libération explicite de connexion.
Je n'ai pas de réponse complète pour vous, mais votre problème est que vous avez supprimé la connexion de façon incorrecte. Vous voulez probablement le mettre dans une structure de type lecteur, de sorte qu'il peut être passé à chaque requête. – jrockway
Hmm, les opérations SQL sont toutes bloquées dans la monade 'IO', donc peut-être' ReaderT IO'? Semble raisonnable. – ephemient