无论如何,这是一个答案,而不是我需要在 SO 中提出的问题。我一直在努力解决这个问题(“在PostgreSQL数据库中使用soci库时如何关闭自动提交”),并提出了几种解决方案。
在Oracle中,默认情况下,自动提交选项处于关闭状态,我们必须显式调用soci::session::commit
来提交已完成的事务,但是在PostgreSQL中,这是另一种方法,它将在执行后立即提交一条sql语句(如果我错了,请纠正我)。当我们独立编写应用程序数据库时,这将带来问题。社会图书馆提供soci::transaction
来解决这个问题。
因此,当我们通过向其提供soci::transaction
来初始化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();
}
但是,执行commit
或rollback
将结束交易tr
,我们需要初始化另一个soci::transaction
以便保留将来的交易(以创建正在进行的交易交易)。这是有关soci::transaction
的更多有趣事实。
soci::transaction
只能有一个soci::session
实例。如果初始化另一个,第二个将替换第一个。commit
不能执行多个rollback
或soci::transaction
。您将在第二次提交或回滚时收到异常。transaction
,然后使用session::commit
或session::rollback
。它将得到与transaction::commit
或transaction::rollback
相同的结果。但是,一旦您照常执行单次提交或回滚,事务将立即结束。soci::transaction
对象对于您的范围(在其中执行sql并调用commit或rollback)以保持您所做的数据库事务直到显式提交或回滚之前的可见性都没有关系。换句话说,如果transaction
中有一个活动的session
正在运行,则数据库事务将一直保留,直到我们显式提交或回滚为止。transaction
创建的session
实例的生命周期结束了,我们就不能指望数据库事务会暂停。soci::transaction::commit
或soci::transaction::rollback
来执行提交或回滚。现在,我将发布我想出的解决方案,以便对任何数据库后端启用显式提交或回滚。
答案 0 :(得分: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 sql
替换为mysociutils::session sql
,并享受SET AUTOCOMMIT OFF
。