Sono un programmatore Java che impara Haskell.
Lavoro su una piccola web-app che utilizza Happstack e dialoga con un database tramite HDBC.Pool di connessioni DB simultanee in Haskell
ho scritto selezionare e exec funzioni e le uso come questo:
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
Molto semplice, come si vede. C'è query, parametri e risultato.
La creazione della connessione e il commit/rollback sono nascosti all'interno di select ed exec.
Questo è buono, non voglio preoccuparmene nel mio codice "logico".
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)
punti negativi:
- una nuova connessione viene sempre creato per ogni chiamata - Questo uccide le prestazioni su carichi pesanti
- DB url "users.db" è codificata - non posso riutilizzare queste funzioni attraverso altri progetti w/o modifica
DOMANDA 1: come introdurre un pool di connessioni wi un numero definito (minimo, massimo) di connessioni simultanee, quindi le connessioni verranno riutilizzate tra le chiamate select/exec?
DOMANDA 2: Come rendere configurabile la stringa "users.db"? (Come spostarlo sul codice cliente?)
Dovrebbe essere una funzione trasparente: il codice utente non dovrebbe richiedere la gestione/rilascio della connessione esplicita.
Non ho una risposta completa per te, ma il tuo problema è che hai distratto la connessione in modo errato. Probabilmente vuoi metterlo in una struttura simile a Reader, in modo che possa essere passato a ogni query. – jrockway
Hmm, le operazioni SQL sono tutte bloccate nella monade 'IO', quindi forse' ReaderT IO'? Sembra ragionevole. – ephemient