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-être
regretière io code>? Semble raisonnable.