0

这是一个答案,而不是我需要在SO中说明的问题。我一直在为这个问题(“如何在将 soci 库与 PostgreSQL 数据库一起使用时关闭自动提交”)苦苦挣扎,并想出了几个解决方案。

在 Oracle 中,默认情况下自动提交选项是关闭的,我们必须soci::session::commit显式调用以提交我们所做的事务,但在 PostgreSQL 中这是另一种方式,它会在我们执行 sql 语句时立即提交(纠正我,如果我错了)。这将在我们独立编写应用程序数据库时引入问题。soci 库提供soci::transaction了为了解决这个问题。

soci::transaction因此,当我们通过提供to 来初始化 a 时soci::session,它将保存我们所做的事务而不提交到数据库。最后,当我们调用soci::transaction::commit它时,它会将更改提交到数据库。

soci::session sql(CONNECTION_STRING);
soci::transaction tr(sql);
try {
    sql << "insert into soci_test(id, name) values(7, \'John\')";
    tr.commit();
}
catch (std::exception& e) {
    tr.rollback();
}

但是,执行commitrollback将结束事务tr,我们需要初始化另一个soci::transaction以保存我们即将进行的未来事务(创建一个活跃的进行中的事务)。这里有更多有趣的事实soci::transaction

  1. soci::transaction每个soci::session. _ 如果您初始化另一个,第二个将替换第一个。
  2. 您不能执行多于一个commitrollback使用一个soci::transaction. 在您第二次提交或回滚时,您将收到一个异常。
  3. 您可以初始化 a transaction,然后使用session::commitor session::rollback。它将给出与transaction::commitor相同的结果transaction::rollback。但是,只要您像往常一样执行单次提交或回滚,事务就会结束​​。
  4. 对象对您的范围(执行 sql 并调用提交或回滚的地方)的可见性无关紧要soci::transaction,以便保留您所做的数据库事务,直到显式提交或回滚。换句话说,如果 a 有一个transaction正在进行的活动session,则 db 事务将一直保持,直到我们明确提交或回滚。
  5. 但是,如果为transaction它创建的实例的生命周期session结束,我们不能期望数据库事务会停止。
  6. 如果您每个人都遭受“警告:没有正在进行的事务”,您必须仅使用soci::transaction::commitor执行提交或回滚soci::transaction::rollback

现在我将发布我想出的解决方案,以便使用任何数据库后端启用显式提交或回滚。

4

1 回答 1

0

这是我想出的解决方案。

namespace mysociutils
{
    class session : public soci::session
    {
    public:
        void open(std::string const & connectString)
        {
            soci::session::open(connectString);
            tr = std::unique_ptr<soci::transaction>(new soci::transaction(*this));
        }

        void commit()
        {
            tr->commit();
            tr  = std::unique_ptr<soci::transaction>(new soci::transaction(*this));
        }

        void rollback()
        {
            tr->rollback();
            tr  = std::unique_ptr<soci::transaction>(new soci::transaction(*this));
        }        

        void ~session()
        {
            tr->rollback();
        }

    private:
        std::unique_ptr<soci::transaction> tr;
    };
}

当执行提交或回滚时,初始化一个新的soci::transaction. 现在您可以替换soci::session sqlmysociutils::session sql并享受SET AUTOCOMMIT OFF.

于 2019-06-18T05:51:25.450 回答