odb(object-relational mapping)是 c++ 领域成熟的 orm 框架,由 code synthesis 开发,能将 c++ 对象与关系型数据库(如 mysql、postgresql、sqlite)无缝映射,避免手动编写 sql 语句,大幅提升数据库开发效率。本文从基础概念到实战开发,全面讲解 odb 的使用。
一、odb 核心概念与环境准备
1. orm 与 odb 简介
orm(对象关系映射)的核心是 “对象 - 表映射”:c++ 类对应数据库表,类成员对应表字段,对象实例对应表中的行。odb 作为 c++ 专属 orm,具备以下特性:
- 支持主流数据库(mysql、postgresql、sqlite、oracle 等);
- 编译期代码生成,无运行时开销;
- 支持事务、关联映射(一对一、一对多)、继承映射等高级特性;
- 轻量级,仅需链接 odb 库,无额外依赖。
2. 环境搭建
(1)安装 odb 工具链
- 下载 odb 编译器:从code synthesis 官网下载对应平台的 odb 编译器(
odb命令行工具); - 安装数据库驱动:如 mysql 需安装
libmysqlclient,postgresql 需安装libpq; - 配置 c++ 编译环境:确保编译器支持 c++11 及以上(如 gcc、clang、msvc)。
(2)项目依赖
- 链接 odb 核心库(
odb)和对应数据库驱动库(如odb-mysql、odb-sqlite); - 包含 odb 头文件路径(
#include <odb/database.hxx>等)。
二、odb 入门:简单对象映射
1. 定义持久化类
首先定义一个 c++ 类,通过 odb 注解标记为 “持久化类”,并指定表名、字段属性:
// person.hxx
#include <string>
#include <odb/core.hxx> // odb核心头文件
// 标记为持久化类,对应数据库表"person"
#pragma db object table("person")
class person
{
public:
person() {} // 必须提供默认构造函数
person(const std::string& name, int age, const std::string& email)
: name_(name), age_(age), email_(email) {}
// 访问器方法
const std::string& name() const { return name_; }
int age() const { return age_; }
const std::string& email() const { return email_; }
private:
// 主键(auto表示自增)
#pragma db id auto
unsigned long id_;
// 普通字段(可指定列名、约束,如not_null)
#pragma db column("name") not_null
std::string name_;
#pragma db column("age")
int age_;
#pragma db column("email") unique // 唯一约束
std::string email_;
// odb需要访问私有成员,声明友元
friend class odb::access;
};2. 生成数据库访问代码
odb 通过编译器(odb命令)分析注解,生成持久化类的数据库操作代码:
# 针对mysql生成代码,输出person-odb.hxx和person-odb.cxx odb -d mysql --generate-query --generate-schema person.hxx
-d mysql:指定数据库类型(可选sqlite、pgsql等);--generate-query:生成查询支持代码;--generate-schema:生成建表 sql 语句。
3. 基础数据库操作(crud)
(1)初始化数据库连接
#include <odb/database.hxx>
#include <odb/mysql/database.hxx> // mysql驱动
// 创建数据库连接(mysql示例)
std::unique_ptr<odb::database> db(
new odb::mysql::database(
"root", // 用户名
"password", // 密码
"test_db", // 数据库名
"localhost", // 主机
3306 // 端口
)
);(2)插入数据(create)
#include "person-odb.hxx" // 生成的代码
person p("alice", 25, "alice@example.com");
odb::transaction t(db->begin()); // 开启事务
db->persist(p); // 插入对象到数据库
t.commit(); // 提交事务(3)查询数据(read)
主键查询:
odb::transaction t(db->begin()); std::shared_ptr<person> p = db->load<person>(1); // 根据主键1查询 std::cout << "name: " << p->name() << ", age: " << p->age() << std::endl; t.commit();
条件查询:
#include <odb/query.hxx>
#include <odb/session.hxx>
odb::session s; // 查询需开启session
odb::transaction t(db->begin());
// 构建查询:age > 20 且 name like 'a%'
odb::query<person> q(
odb::query<person>::age > 20 &&
odb::query<person>::name.like("a%")
);
// 执行查询并遍历结果
for (auto& p : db->query<person>(q))
std::cout << p.name() << ": " << p.email() << std::endl;
t.commit();(4)更新数据(update)
odb::transaction t(db->begin()); std::shared_ptr<person> p = db->load<person>(1); p->age_ = 26; // 修改对象(需将age_改为public或提供setter) db->update(*p); // 更新数据库 t.commit();
(5)删除数据(delete)
odb::transaction t(db->begin()); db->erase<person>(1); // 根据主键删除 t.commit();
三、odb 进阶特性
1. 关联映射
(1)一对一关联(one-to-one)
例如person关联address:
// address.hxx
#pragma db object
class address
{
// ... 字段定义(主键id_,street_,city_等)
};
// person.hxx中添加关联
#pragma db object
class person
{
// ... 其他字段
#pragma db one_to_one // 一对一关联
odb::lazy_ptr<address> address_; // 懒加载(访问时才查询)
};(2)一对多关联(one-to-many)
例如department包含多个employee:
// employee.hxx
#pragma db object
class employee
{
// ... 字段
#pragma db many_to_one // 多对一(反向关联)
odb::ptr<department> dept_;
};
// department.hxx
#pragma db object
class department
{
// ... 字段
#pragma db one_to_many(mapped_by = "dept_") // 一对多,指定反向关联字段
std::vector<odb::ptr<employee>> employees_;
};2. 继承映射
odb 支持类继承的表映射,分为三种策略:
- 单表策略:所有子类映射到同一张表(通过
discriminator区分); - joined 策略:父类和子类分别映射到不同表,查询时关联;
- table-per-class 策略:每个子类映射到独立表。
示例(单表策略):
#pragma db object abstract // 抽象父类
class user
{
#pragma db id auto
unsigned long id_;
std::string username_;
};
#pragma db object
class adminuser : public user
{
std::string role_;
};
#pragma db object
class normaluser : public user
{
std::string avatar_;
};3. 事务与并发
odb 支持事务的 acid 特性,可通过odb::transaction控制:
odb::transaction t(db->begin());
try
{
// 批量操作
db->persist(p1);
db->persist(p2);
t.commit();
}
catch (const odb::exception& e)
{
t.rollback(); // 异常时回滚
std::cerr << "transaction failed: " << e.what() << std::endl;
}四、实战案例:用户管理系统
1. 需求分析
实现一个简单的用户管理系统,支持用户的增删改查、角色关联(用户 - 角色一对多)。
2. 核心代码实现
(1)定义持久化类
// role.hxx
#pragma db object
class role
{
public:
role(const std::string& name) : name_(name) {}
private:
friend class odb::access;
role() {}
#pragma db id auto
unsigned long id_;
#pragma db not_null unique
std::string name_; // 角色名:admin, user
};
// user.hxx
#pragma db object
class user
{
public:
user(const std::string& name, int age) : name_(name), age_(age) {}
private:
friend class odb::access;
user() {}
#pragma db id auto
unsigned long id_;
#pragma db not_null
std::string name_;
int age_;
#pragma db many_to_many // 多对多关联角色
std::vector<odb::ptr<role>> roles_;
};(2)生成代码并编译
odb -d sqlite --generate-query --generate-schema role.hxx user.hxx g++ -c user-odb.cxx role-odb.cxx main.cxx -i/path/to/odb/include -l/path/to/odb/lib -lodb -lodb-sqlite
(3)业务逻辑实现
#include <odb/sqlite/database.hxx>
#include "user-odb.hxx"
#include "role-odb.hxx"
int main()
{
// sqlite数据库(文件test.db)
std::unique_ptr<odb::database> db(new odb::sqlite::database("test.db"));
// 1. 创建角色
odb::transaction t1(db->begin());
db->persist(role("admin"));
db->persist(role("user"));
t1.commit();
// 2. 创建用户并关联角色
odb::transaction t2(db->begin());
auto admin_role = db->query_one<role>(odb::query<role>::name == "admin");
user u("bob", 30);
u.roles_.push_back(admin_role);
db->persist(u);
t2.commit();
// 3. 查询用户及其角色
odb::session s;
odb::transaction t3(db->begin());
auto user = db->load<user>(1);
std::cout << "user: " << user->name_ << ", roles: ";
for (auto& r : user->roles_)
std::cout << r->name_ << " ";
t3.commit();
return 0;
}五、odb 最佳实践与注意事项
- 避免过度封装:简单查询直接使用 odb 的
query接口,复杂 sql 可通过odb::query的raw()方法嵌入原生 sql; - 懒加载优化:关联对象默认懒加载,批量查询时可通过
odb::join主动关联,减少数据库请求; - 性能考量:编译期生成代码无运行时开销,但频繁的对象持久化需注意事务批量处理;
- 数据库迁移:使用
--generate-schema生成的 sql 文件管理表结构,配合版本控制实现迁移; - 异常处理:捕获
odb::exception及其子类(如odb::sql_exception),处理数据库错误。
六、总结
odb 作为 c++ 的高效 orm 框架,通过编译期代码生成实现了对象与数据库的无缝映射,既保留了 c++ 的性能优势,又简化了数据库操作。从简单的 crud 到复杂的关联映射、事务管理,odb 都能提供优雅的解决方案,是 c++ 后端开发中替代原生 sql 的理想选择。掌握 odb 的核心用法,可大幅提升项目的开发效率和可维护性。
到此这篇关于c++ odb orm 从入门到实战应用的文章就介绍到这了,更多相关c++ odb orm 内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论