鉴于 runDB 的以下定义,第二个插入是否会在第一个失败时回滚?

Given the below definition of runDB, will the second insert rollback upon failure of the first?

我使用 Yesod 作为框架,使用 postgresql 作为数据库,并且有以下 runDB 的定义。查看 Yesod 站点上的文档,我有一种预感,以下列方式使用 runDB 将导致第一个 insert 在第二个失败时回滚。我对吗。如果没有,我该如何调用回滚?

instance YesodPersist App where
    <snip>
    runDB action = do
        master <- getYesod
        runSqlPool action $ appConnPool master


addKitteh :: Kitteh -> Handler (Either StoreError StoreResult)
addKitteh (Kitteh desc color size photo) = do
    data_key <- runDB $ do
                         data_key <- insert (KittehDesc desc color size)
                         insert (KittehPic data_key photo)
...

编辑 - 另外,如果第一个 insert 失败会怎样?

编辑 - 我认为该模型可能很重要

KittehDesc json
   blurb Text
   color Color
   size KittehSize
   deriving Show

KittehPic
  kittehId KittehDescId Eq
  kittehPic Base64
  UniqueKittehId kittehId

是的,runDB 中的所有内容都包含在交易中。如果第一次插入失败会抛出异常,代码不会到达第二次插入。

我认为这在某处有记录,但我只是跟踪代码得出这个结论:runDB 是用 defaultRunDB, which calls into runPool 实现的,它调用 runSqlPool,它调用 runSqlConn,可以看到是在异常发生时处理回滚:

runSqlConn :: MonadBaseControl IO m => SqlPersistT m a -> SqlBackend -> m a
runSqlConn r conn = control $ \runInIO -> mask $ \restore -> do
    let getter = getStmtConn conn
    restore $ connBegin conn getter
    x <- onException
            (restore $ runInIO $ runReaderT r conn)
            (restore $ connRollback conn getter)
    restore $ connCommit conn getter
    return x