Отключить автокоммит в PostgreSQL с помощью SOCI C ++ - PullRequest
0 голосов
/ 18 июня 2019

Это скорее ответ, чем вопрос, который мне все равно нужно сформулировать в SO .Я долго боролся с этим вопросом («как отключить автокоммит при использовании библиотеки soci с базами данных PostgreSQL») и придумал несколько решений.

В Oracle по умолчанию опция автоматической фиксации отключена, и нам нужно явно вызвать soci::session::commit, чтобы зафиксировать транзакции, которые мы сделали, но в PostgreSQL это происходит наоборот, и он будет зафиксирован, как только мывыполнить SQL-оператор (поправьте меня, если я не прав).Это создаст проблемы, когда мы создадим базу данных приложений самостоятельно.Библиотека soci предоставляет 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.

  1. Вы можете иметь только один soci::transaction экземпляр на soci::session.Второй заменит первый, если вы инициализируете другой.
  2. Вы не можете выполнить более одного commit или rollback, используя soci::transaction.Вы получите исключение при втором коммите или откате.
  3. Вы можете инициализировать transaction, затем использовать session::commit или session::rollback.Это даст тот же результат, что и transaction::commit или transaction::rollback.Но транзакция завершится, как только вы выполните обычную фиксацию или откат как обычно.
  4. Не имеет значения видимость объекта soci::transaction для вашей области (где вы выполняете sql и вызываете commit или rollback), чтобы удерживать транзакции БД, которые вы сделали, до явного подтверждения или отката.Другими словами, если для session идет активный transaction, транзакции в дБ будут удерживаться до тех пор, пока мы явно не зафиксируем или не откатаемся.
  5. Но, если время жизни экземпляра transaction, который создалпоскольку session был окончен, мы не можем ожидать, что транзакции БД будут остановлены.
  6. Если вы все страдаете от «ПРЕДУПРЕЖДЕНИЕ: транзакция не выполняется», вы должны выполнять фиксацию или откат только с помощью soci::transaction::commit или soci::transaction::rollback.

Теперь я опубликую решение, которое я придумала, чтобы включить явную фиксацию или откат с любым бэкэндом базы данных.

1 Ответ

0 голосов
/ 18 июня 2019

Это решение, которое я придумал.

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.

...