Je suis un programmeur Java qui apprends Haskell.
Je travaille sur une petite application Web qui utilise Happstack et parle à une base de données via HDBC.
J'ai écrit 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)
3 Réponses :
Ouvrir la connexion Question 1: strong> HMM, un pool de connexion ne semble pas si difficile à mettre en œuvre ... P> Code > Quelque part en dehors de la fonction et ne le déconnectez pas dans la fonction. P> connPool <- newConnPool 0 50 (connectSqlite3 "user.db") disconnect
Frais! Est-ce que c'est le fil sûr? Est-il correct de créer un seul "connpool" et l'utiliser dans tous les gestionnaires de fichiers?
Il devrait s'agir de thread-coffre-fort, tout le travail est effectué dans ModifyMvar code> (qui est Takemvar code> + putmvar code>), qui séquence efficacement tout le Prendre code> / mettre les opérations code>. Mais vous devez vraiment vérifier ce code vous-même, pour voir s'il convient à vos besoins.
Avant d'utiliser le test de la piscine Comment votre pilote de base de données s'échappe avec des déconnectes. J'ai essayé d'utiliser cette mise en œuvre de cette piscine avec le pilote HDBC-ODBC contre MS SQL Server. Ça fonctionne bien. Mais ensuite, j'arrête SQL Server, essayez l'application, ce qui me donne évidemment l'erreur, puis démarrez SQL Server Retour et essayez à nouveau l'application. Cela donne toujours une erreur. Malheureusement, se déconnectent sur le réseau se produisent. Assurez-vous donc de gérer des connexions défectueuses et de paver de nouvelles.
J'ai modifié le code ci-dessus, il est maintenant capable de compiler au moins.
module ConnPool ( newConnPool, withConn, delConnPool ) where
import Control.Concurrent
import Control.Exception
import Control.Monad (replicateM)
import Database.HDBC
data Pool a =
Pool { poolMin :: Int, poolMax :: Int, poolUsed :: Int, poolFree :: [a] }
newConnPool :: Int -> Int -> IO a -> (a -> IO ()) -> IO (MVar (Pool a), IO a, (a -> IO ()))
newConnPool low high newConn delConn = do
-- cs <- handleSqlError . sequence . replicate low newConn
cs <- replicateM low newConn
mPool <- newMVar $ Pool low high 0 cs
return (mPool, newConn, delConn)
delConnPool (mPool, newConn, delConn) = do
pool <- takeMVar mPool
if length (poolFree pool) /= poolUsed pool
then putMVar mPool pool >> fail "pool in use"
else mapM_ delConn $ poolFree pool
takeConn (mPool, newConn, delConn) = modifyMVar mPool $ \pool ->
case poolFree pool of
conn:cs ->
return (pool { poolUsed = poolUsed pool + 1, poolFree = cs }, conn)
_ | poolUsed pool < poolMax pool -> do
conn <- handleSqlError newConn
return (pool { poolUsed = poolUsed pool + 1 }, conn)
_ -> fail "pool is exhausted"
putConn :: (MVar (Pool a), IO a, (a -> IO b)) -> a -> IO ()
putConn (mPool, newConn, delConn) conn = modifyMVar_ mPool $ \pool ->
let used = poolUsed pool in
if used > poolMin pool
then handleSqlError (delConn conn) >> return (pool { poolUsed = used - 1 })
else return $ pool { poolUsed = used - 1, poolFree = conn : (poolFree pool) }
withConn connPool = bracket (takeConn connPool) (putConn connPool)
Le Package de ressource-piscine fournit un pool de ressources hautes performances pouvant être utilisé pour la mise en commun de la connexion de base de données. Par exemple:
import Data.Pool (createPool, withResource)
main = do
pool <- createPool newConn delConn 1 10 5
withResource pool $ \conn -> doSomething conn
Je viens d'utiliser (et que je suis aimant) data.conuit.pool (paquet de conduits de pool). C'est un wrapper autour de données.pool (utilisé par Yesod et d'autres personnes) Hackage.hakell. org / colis / piscine-conduit-0.1.1
Je n'ai pas de réponse complète pour vous, mais votre problème est que vous avez abstraité de manière incorrecte la connexion. Vous voulez probablement le mettre dans une structure ressemblant à un lecteur, de sorte qu'elle puisse être transmise à chaque requête.
HMM, SQL Les opérations sont toutes bloquées dans le
io code> monad, donc peut-êtreregretière io code>? Semble raisonnable.