首页 > 开源 > C++ Web 开发框架 Paozhu 发布 1.16.0,添加 PostgreSQL SQLite 支持

C++ Web 开发框架 Paozhu 发布 1.16.0,添加 PostgreSQL SQLite 支持

OSChina资讯 2026-09-12 20:08 3 阅读 查看原文

C++ web开发框架 paozhu 发布1.16.0发布,ORM添加PostgreSQL SQLite支持,纯自研客户端。PostgreSQL客户端框架来自MySQL成熟流程架构,支持socket,ssl,unix.sock三种模式
业务代码无缝在三个数据库切换,同时支持同步、异步(协程)模式。
Paozhu ORM 目前支持MySQL MariaDB PostgreSQL SQLite 四种数据库,同时支持同步和C++20标准协程,支持文本模式和预编译语句(Prepared Statements)模式。
整个项目无需使用官方客户端,而且稳定支持协程。

  • 采用自研数据库连接协议,支持 MySQL PostgreSQL 和 SQLite,无需额外安装 MySQL Connector/C++ 或 libpq
  • 支持 MySQL 8.0.4 以上版本(支持 caching_sha2_password 认证插件)
  • 支持 MariaDB 12.1+(12.1 版本开始支持 caching_sha2_password 认证插件,与 MySQL 8.0 默认认证方式兼容)
  • 自研协议同时支持 C++20 协程(异步)同步两种调用方式,可在同一项目中混用
  • 使用 CLI 工具在数据库类型之间迁移数据(如 MySQL/CMS 迁移到 PostgreSQL),目标库的表会被自动创建:数据库之间迁移( MySQL <=> PostgreSQL <=> SQLite)
  • # 从 cms 迁移到 pg (cms是mysql标签,pg是PostgreSQL配置标签)
    ./bin/paozhu_cli dbconver cms pg

     

自动支持foreign keys 外键关系,支持one many模式。

//@urlpath(null,test_ormfk_one)
std::string test_ormfk_one(std::shared_ptr<httppeer> peer)
{
    httppeer &client = peer->get_peer();

    auto child = orm::FkChild();
    child.where(orm::fk_child_info::cols::id, 1);
    child.fetch_one();
    client << "<p>child id:" << child.data.id << " parent_id:" << child.data.parent_id << "</p>";

    // outgoing: fk_child.parent_id -> fk_parent.id, scoped by current row data
    auto parent = child.oneFkParent();
    parent.fetch_one();
    client << "<p>oneFkParent sql:" << parent.sqlstring << "</p>";
    client << "<p>oneFkParent name:" << parent.data.name << "</p>";

    // explicit id overload
    auto parent2 = child.oneFkParent(2);
    parent2.fetch_one();
    client << "<p>oneFkParent(2) name:" << parent2.data.name << "</p>";

    // overload that decorates an existing model, so extra conditions still chain
    auto decorated = orm::FkParent();
    child.oneFkParent(decorated);
    decorated.select("id,name");
    decorated.fetch_one();
    client << "<p>oneFkParent(obj&) sql:" << decorated.sqlstring << "</p>";
    return "";
}

多对多模式

//@urlpath(null,test_ormfk_many)
std::string test_ormfk_many(std::shared_ptr<httppeer> peer)
{
    httppeer &client = peer->get_peer();

    auto parents = orm::FkParent();
    parents.fetch();
    client << "<p>parents:" << parents.record.size() << "</p>";

    // incoming: fk_child.parent_id -> fk_parent.id, scoped by every id in record
    auto children = parents.manyFkChild();
    children.fetch();
    client << "<p>manyFkChild sql:" << children.sqlstring << "</p>";
    client << "<p>manyFkChild rows:" << children.record.size() << "</p>";

    // group in memory to avoid the N+1 round trip
    std::vector<int> child_count;
    for (auto &p : parents.record)
    {
        int n = 0;
        for (auto &c : children.record)
        {
            if (c.parent_id == p.id)
            {
                n++;
            }
        }
        child_count.emplace_back(n);
    }
    for (size_t i = 0; i < parents.record.size(); i++)
    {
        client << "<p>parent " << parents.record[i].id << " name:" << parents.record[i].name
               << " children:" << child_count[i] << "</p>";
    }

    auto decorated = orm::FkChild();
    parents.manyFkChild(decorated);
    decorated.where(orm::fk_child_info::cols::extra, orm::wq::nq, "");
    decorated.fetch();
    client << "<p>manyFkChild(obj&) sql:" << decorated.sqlstring << "</p>";
    return "";
}

预处理模式,有exec_标志

namespace orm::cust
{
    struct WorldRowStruct : orm::Base<WorldRowStruct>
    {
        unsigned int id;
        int randomnumber;
        ORM_NAMES(id, randomnumber);
    };
}// namespace orm::cust

namespace http
{
//@urlpath(null,test_ormprepared_exec)
std::string test_ormprepared_exec(std::shared_ptr<httppeer> peer)
{
    httppeer &client = peer->get_peer();

    auto world = orm::World();
    world.AND("id", orm::wq::be, 1)
         .AND("id", orm::wq::le, 200)
         .orsub()
         .AND("randomnumber", orm::wq::bt, 5000)
         .OR("randomnumber", orm::wq::lt, 200)
         .endsub();

    unsigned int total = world.exec_count();
    client << "<p>count:" << total << "</p>";

    world.select("id,randomnumber");
    std::vector<orm::cust::WorldRowStruct> rows;
    world.exec_fetch_to(rows);

    client << "<p>" << world.sqlstring << "</p>";
    client << "<p>fetched:" << rows.size() << " error:" << world.error_msg << "</p>";
    for (auto &row : rows)
    {
        client << "<p>" << row.to_json() << "</p>";
    }
    return "";
}
}

预编译路径(值作为参数绑定)—— 每个 exec_ 方法都有一个签名与返回值完全 一致的 async_exec_ 版本:

同步方法 异步方法
exec_count() async_exec_count()
exec_page() async_exec_page()
exec_fetch() async_exec_fetch()
exec_fetch_to(rows) async_exec_fetch_to(rows)
exec_fetch_append() async_exec_fetch_append()
exec_one() async_exec_one()
exec_one_to(rec) async_exec_one_to(rec)
exec_one_append(vec) async_exec_one_append(vec)
exec_insert() async_exec_insert()
exec_insert_batch() async_exec_insert_batch()
exec_update() async_exec_update()
exec_update_dirty() async_exec_update_dirty()
exec_update_col() async_exec_update_col()
exec_replace_col() async_exec_replace_col()
exec_remove() async_exec_remove()

新加入脏检查
exec_update_dirty() async_exec_update_dirty() 自动更新需要更新的字段

文本路径(值被转义进语句):

同步方 异步方法 说明
fetch() async_fetch() 查询所有匹配记录
fetch_one() async_fetch_one() 查询单条记录
fetch_append() async_fetch_append() 查询并追加到现有结果集
count() async_count() 统计匹配记录数
save() async_save() 新增记录
update() async_update() 更新记录
update_dirty()

 

async_update_dirty()

 

只更新经生成的逐字段 setter 写过的列
remove() async_remove() 删除

官方地址 
https://github.com/hggq/paozhu