我完全错过了数据库打开连接和回滚功能的要点,所以runDB myAction
每次都在使用,因为我不知道发生了什么。今天,我进行了一些测试以试图了解它是如何进行回滚的,其中之一是:
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
被回滚,当我插入另一个注册表时,其ID从最后一个持久元素前面的9个位置开始。
假设我必须get
在数据库中执行2项操作,并且以两种方式执行它们,第一种是:
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
从未使用过,因此也不会查询它们)。这些问题可能看起来很废话,但是我想确保我的理解没有空白。
我认为您在讨论两个数据库操作时已经回答了自己的问题。“ runDB”具有以下签名。
runDB :: YesodDB site a -> HandlerT site IO a
YesodDB
是ReaderT变压器monad。runDb将DB操作提升为IO操作。在第一个示例中,有两个单独的IO操作(不是DB操作)。在第二个片段中,只有一个数据库操作。在第一个示例中,一个或两个动作都可能成功。但是在第二个中,您将得到2 get
s的结果或一个错误。
由于有两个IO
包裹两个runDB
s的动作,因此无法优化数据库交互,因为每个runDB代表一个动作。然而,第二步,这两个动作将共享相同的连接。
您可能需要查看YesodPersistentBackend并使用getDBRunner来共享来自池的连接。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句