2016-04-16 5 views
2

Мне не хватало точки открытия базы данных и функции отката, поэтому я использовал runDB myAction каждый раз, потому что я не понимал, что происходит. Сегодня я сделал некоторые тесты, чтобы попытаться понять, как это делает откат, и один из них был такой:Yesod Постоянное атомное взаимодействие

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" 

Я получил undefined ошибку во время выполнения, как и ожидалось, и только первые runDB действия получили в базе данных , второй runDB откинулся назад, и когда я вставил другой реестр, его идентификатор начинался с 9 позиций впереди последнего сохраняемого элемента.

Предположим, что я должен сделать 2 get сек действия в базе данных, и я их двумя способами, первый я:

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

, а затем я пытаюсь:

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" 

Какой бы быть фактической общей разницей? Я думаю, что в этом случае консистенция базы данных не является проблемой, но производительность может быть (или будет ленивость Haskell делает их равными, потому что mfoo и mboo никогда не используются, чтобы они никогда не запрашивались?). Вероятно, эти вопросы выглядят очень глупо, но я хотел бы быть уверенным, что у меня нет пробелов в моем понимании.

+0

Haskell очень велик, я думаю, что ум программиста, который был открыт для Haskell в течение довольно хорошего времени, никогда не вернется в свое первоначальное состояние. Это похоже на программирование с повышенной мощностью, постоянно совершенствующееся в наших собственных умах и, следовательно, в нашем общем кодировании. – FtheBuilder

ответ

3

Я думаю, что вы ответили на свой вопрос, обсуждая два действия БД. «runDB» имеет следующую подпись.

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

YesodDB представляет собой трансформатор монада ReaderT. runDb активирует действие DB для действия IO. В первом примере есть два отдельных действия IO (не действие DB). Во втором фрагменте есть только одно действие DB. В первом примере одно или оба действия могут быть успешными. Но во втором вы получите либо результат двух get с, либо ошибку.

Как есть два действия IO, обертывающие два runDB, взаимодействие БД не оптимизировано, так как каждый runDB представляет одно действие. Во втором, однако, оба действия будут использовать одно и то же соединение.

Возможно, вы захотите взглянуть на YesodPersistentBackend и использовать getDBRunner для совместного использования соединения из пула.

+0

Можете ли вы лучше объяснить эту часть: «В первом примере есть два отдельных действия IO (не действие БД)». – FtheBuilder

+1

runDB полагается на связанный backend tyoe, который по умолчанию соответствует типу SqlBackend постоянной системы, runDb по существу вызовет runSqlPool для выполнения действия. runSQLpool получает соединение из пула, запускает действие и возвращает соединение. (Нет повторного использования соединения). Следовательно, два runDB означают, что для каждого используются два соединения. –

Смежные вопросы