如何与 libpqxx API 同时插入数据? (PostgreSQL,线程)

How To Insert Data concurrently with the libpqxx API? (PostgreSQL,threads)

使用的东西:

图书馆:libpqxx:x64-windows version 6.4.4

OS: Windows 10

编译器:Visual C++ (MSVC)

这是我的 SQL Table:

CREATE TABLE test(
    test_name VARCHAR(16)
);

这是我的简约测试版:

main.cpp

#include <pqxx/pqxx> 
#include "test.h"
int main()
{

    pqxx::connection database_connection("dbname = test user = postgres password = *****\
      hostaddr = 127.0.0.1 port = 5432");


    database_connection.prepare("insert_into_table", "INSERT INTO test \
    VALUES ()");

    test test(&database_connection);

    system("pause");
}

test.h

#pragma once
#include <pqxx/connection.hxx>
#include <thread>
#include <array>
class test
{
public:
    explicit test(pqxx::connection* database_connection);
    void InsertData();

    std::array<std::thread, 1> threads{};
    pqxx::connection* database_connection;
};

test.cpp

#include "test.h"
#include <iostream>
#include <pqxx/transaction.hxx>

test::test(pqxx::connection* database_connection) : database_connection(database_connection)
{
    for (auto& i : threads)
    {
        i = std::thread(&test::InsertData, this);
    }
}


void test::InsertData()
{

    pqxx::work work(*database_connection);
    try
    {

        pqxx::result result = work.exec_prepared("insert_into_table", "test_data"); //prepared data in real project pqxx::binarystring blobs

        work.commit();

    }
    catch (const std::exception& e) {
        work.abort();
    }

}

将 test.h 中的线程大小更改为任何大于 1 的值都会导致。

注意:我必须使用准备好的 SQL 语句稍后将原始 bytea 数据插入我的 table。

输出:

Exception thrown at 0x00007FFC2FF44008 in Project3.exe: Microsoft C++ exception : pqxx::usage_error at memory location 0x000000CEB00FF050.
Exception thrown at 0x00007FFC2FF44008 in Project3.exe: Microsoft C++ exception : pqxx::usage_error at memory location 0x000000CEB03FEF50.
Exception thrown at 0x00007FFC2FF44008 in Project3.exe: Microsoft C++ exception : pqxx::usage_error at memory location 0x000000CEB04FED30.
Exception thrown at 0x00007FFC2FF44008 in Project3.exe: Microsoft C++ exception : pqxx::usage_error at memory location 0x000000CEB02FEAF0.
Debug Error!

如何与此 API 同时插入?

Link 解决方案:https://pqxx.org/development/libpqxx/wiki/Threading

Approaches for thread - safe programs

Approach 1: single database thread
Make one of your threads the dedicated "database thread." Ensure that that thread is the only one that ever accesses objects or functions from libpqxx.Use message - passing to channel all your database interactions through this thread.

This approach should be safe even if your libpq build is not thread - safe.

Approach 2 : global lock
Let multiple threads access objects and functions from libpqxx, but never simultaneously.Use a single, global lock to protect any access to libpqxx.

You do need a lock of some sort.You can't generally rely on other ways to know that thread 1 is done before thread 2 uses the library! Data from thread 1 may still be cached in a register or, depending on your system architecture, a processor cache that thread 2 isn't synchronized with.Or vice versa.It gets ugly and subtle.

Approach 3 : thread - local connections
Every connection in libpqxx acts as its own little world.It produces result objects, you create transactions on it, it uses error message callbacksand so forth.Keep all of the objects related to a connection exclusively inside the same thread that created the connection.This way you'll need no locking at all.

Of course you can still have more than one connection inside the same thread.This model should be fine for most applications, so this is probably as far as you'll want to read.

Approach 4 : per - connection locking
If you really have to share any libpqxx objects at all between threads, set up one lock per connection.This lock should protect all objects related to that connection.That way, all access to a connectionand its related objects will be serialized as if they all stayed in the same thread.

The risk of deadlocks may be slightly greater if you go this way.

在我的例子中,我将连接更改为

static thread_local database_connection;

所以每个线程都有自己的连接,然后代码无需太多更改即可工作。