C++ web开发框架 paozhu 发布1.16.0发布,ORM添加PostgreSQL SQLite支持
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 协程(异步)和同步两种调用方式,可在同一项目中混用
数据库迁移
数据库之间迁移( MySQL <=> PostgreSQL <=> SQLite)
使用 CLI 工具在数据库类型之间迁移数据(如 MySQL/CMS 迁移到 PostgreSQL),目标库的表会被自动创建:
# 从 cms 迁移到 pg (cms是mysql标签,pg是PostgreSQL配置标签)
./bin/paozhu_cli dbconver cms pg
# 强制迁移(覆盖已有表)
./bin/paozhu_cli dbconver cms pg force
💡 提示:迁移前请确认目标数据库已存在且连接配置正确(
orm.conf)。不带 force 时,如果目标表已存在会跳过,避免误覆盖数据。SQL 导出
将数据库结构或数据导出为 SQL 文件,可用于备份、迁移或分发:
# 导出表结构
./bin/paozhu_cli dbtable cms ./schema.sql
./bin/paozhu_cli dbtable cms ./pg.sql -target=pg # 导出为 PG 语法
# 导出结构+数据
./bin/paozhu_cli dbexport cms ./dump.sql
./bin/paozhu_cli dbexport cms ./mysql.sql -target=mysql
💡 提示:默认导出当前数据源的 SQL 方言,也可通过
-target=pg / -target=mysql 指定目标数据库语法,方便在不同数据库之间迁移。自动支持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

浙公网安备 33010602011771号