2016-04-16 8 views
2

Ich habe den Punkt der Datenbank geöffnet Verbindung und Rollback-Funktion vollständig vermisst, so dass ich runDB myAction jedes Mal verwendet wurde, weil ich nicht wusste, was los war. Heute habe ich einige Tests zu versuchen zu verstehen, wie es das Rollback der Fall ist, und einer von ihnen war:Yesod Persistente atomare Interaktion

getTestR :: Handler Text 
getTestR = do 
runDB $ insert $ Test 0 
runDB $ do 
    forM_ [1..] $ \n -> do 
    if n < 10 
     then do 
     insert $ Test n 
     return() 
     else undefined 
return "completed" 

Ich habe eine undefined Fehler zur Laufzeit, wie erwartet, und nur die erste runDB Aktion bekam in der Datenbank , die zweite runDB wurde zurückgerollt und als ich eine andere Registrierung einfügte, begann seine ID mit 9 Positionen vor dem letzten beibehaltenen Element.

Angenommen, ich habe 2 get s Aktionen in der Datenbank zu tun, und ich tun, um sie auf zwei Arten, zuerst ich tun:

getTestR :: FooId -> BooId-> Handler Text 
getTestR fooid booid = do 
    mfoo <- runDB $ get fooid 
    mboo <- runDB $ get booid 
    return "completed" 

und dann versuche ich:

getTest'R :: FooId -> BooId-> Handler Text 
getTest'R fooid booid = do 
    (mfoo, mboo) <- runDB $ do 
    mfoo <- get fooid 
    mboo <- get booid 
    return (mfoo,mboo) 
    return "completed" 

Welche würden der tatsächliche Gesamtunterschied sein? Ich denke, dass in diesem Fall die Datenbankkonsistenz kein Problem ist, aber die Performance kann sein (oder wird Haskell Faulheit sie gleich machen, weil mfoo und mboo niemals verwendet werden, so dass sie nie abgefragt werden?). Wahrscheinlich sehen diese Fragen sehr unsinnig aus, aber ich möchte sicher sein, dass ich keine Lücken in meinem Verständnis habe.

+0

Haskell ist sehr groß, ich denke, dass der Verstand eines Programmierers, der Haskell während einer ziemlich guten Zeit aussetzt, sich niemals in seinen ursprünglichen Zustand zurückversetzt. Es ist wie Programmierung mit erhöhter Leistung, die ständig Verbesserungen in unseren eigenen Köpfen und folglich in unserer allgemeinen Kodierung macht. – FtheBuilder

Antwort

3

Ich denke, Sie haben Ihre eigene Frage bei der Diskussion von zwei DB-Aktionen beantwortet. 'runDB' hat folgende Signatur.

runDB :: YesodDB site a -> HandlerT site IO a 

YesodDB ist ein ReaderT Transformator monadisch. runDb hebt DB-Aktion auf IO-Aktion auf. Im ersten Beispiel gibt es zwei separate IO-Aktionen (keine DB-Aktion). Im zweiten Snippet gibt es nur eine einzige DB-Aktion. Im ersten Beispiel können eine oder beide Aktionen erfolgreich sein. Aber in der zweiten, erhalten Sie entweder das Ergebnis von zwei get s oder einen Fehler.

Da zwei IO Aktionen zwei runDB s umfassen, ist die DB-Interaktion nicht optimiert, da jede runDB eine einzelne Aktion darstellt. In der Sekunde jedoch haben die zwei Aktionen dieselbe Verbindung.

Sie möchten vielleicht YesodPersistentBackend ansehen und getDBRunner für die Freigabe der Verbindung aus einem Pool verwenden.

+0

Können Sie diesen Teil besser erklären: "Im ersten Beispiel gibt es zwei separate IO-Aktionen (keine DB-Aktion)." – FtheBuilder

+1

runDB hängt vom zugeordneten Back-End-Typ ab, der standardmäßig den SqlBackend-Typ der persistenten Bibliothek verwendet. RunDb würde im Wesentlichen runSqlPool aufrufen, um eine Aktion auszuführen. runSQLpool ruft die Verbindung vom Pool ab, führt die Aktion aus und gibt die Verbindung zurück. (Keine Wiederverwendung der Verbindung). Daher bedeutet zwei runDB, dass für jede Verbindung zwei Verbindungen verwendet werden. –