Skip to content

SOCI — SQL ORM

SOCI 是 C++ 的数据库访问库,提供统一 API 支持 PostgreSQL/MySQL/SQLite/Oracle,语法简洁,支持 ORM 风格映射。

安装

bash
# vcpkg
vcpkg install soci[sqlite3,postgresql,mysql]

# CMake
find_package(SOCI REQUIRED)
target_link_libraries(myapp PRIVATE SOCI::soci_core SOCI::soci_sqlite3)

基本用法

cpp
#include <soci/soci.h>
#include <soci/sqlite3/soci-sqlite3.h>
#include <soci/postgresql/soci-postgresql.h>

// SQLite 连接
soci::session sql(soci::sqlite3, "mydb.db");

// PostgreSQL 连接
soci::session sql2(soci::postgresql,
    "host=localhost dbname=mydb user=postgres password=secret");

// DDL
sql << "CREATE TABLE IF NOT EXISTS users ("
       "id INTEGER PRIMARY KEY AUTOINCREMENT,"
       "name TEXT NOT NULL,"
       "age INTEGER)";

// 插入(流式语法)
std::string name = "Alice";
int age = 30;
sql << "INSERT INTO users (name, age) VALUES (:name, :age)",
       soci::use(name), soci::use(age);

// 获取最后插入 ID
long long id;
sql << "SELECT last_insert_rowid()", soci::into(id);

查询与绑定

cpp
// 单行查询
std::string name;
int age;
sql << "SELECT name, age FROM users WHERE id = :id",
       soci::into(name), soci::into(age), soci::use(1);
std::cout << name << " " << age << "\n";

// 多行查询(rowset)
soci::rowset<soci::row> rs = (sql.prepare <<
    "SELECT id, name, age FROM users WHERE age > :min_age",
    soci::use(18));

for (const auto& row : rs) {
    int id = row.get<int>("id");
    std::string name = row.get<std::string>("name");
    int age = row.get<int>("age");
    std::cout << id << " " << name << " " << age << "\n";
}

自定义类型映射

cpp
struct User {
    int id;
    std::string name;
    int age;
    std::string email;
};

// 特化 type_conversion
namespace soci {
template<>
struct type_conversion<User> {
    using base_type = values;

    static void from_base(const values& v, indicator ind, User& u) {
        u.id    = v.get<int>("id");
        u.name  = v.get<std::string>("name");
        u.age   = v.get<int>("age");
        u.email = v.get<std::string>("email", "");  // 默认值
    }

    static void to_base(const User& u, values& v, indicator& ind) {
        v.set("name",  u.name);
        v.set("age",   u.age);
        v.set("email", u.email);
        ind = i_ok;
    }
};
}

// 使用
User user;
sql << "SELECT id, name, age, email FROM users WHERE id = :id",
       soci::into(user), soci::use(1);
std::cout << user.name << "\n";

// 插入
User new_user{0, "Bob", 25, "bob@example.com"};
sql << "INSERT INTO users (name, age, email) VALUES (:name, :age, :email)",
       soci::use(new_user);

事务

cpp
{
    soci::transaction txn(sql);
    sql << "UPDATE accounts SET balance = balance - 100 WHERE id = 1";
    sql << "UPDATE accounts SET balance = balance + 100 WHERE id = 2";
    txn.commit();
}
// 析构时自动回滚(若未 commit)

关键认知

SOCI 的最大优势是统一 API 支持多种数据库,切换数据库只需改连接字符串。type_conversion 特化实现 ORM 风格的对象映射。语法简洁,适合中小型项目。大型项目考虑专用 ORM 或直接用数据库原生驱动。

系统学习 C++ 生态,深入底层架构