跳到主要内容
C++ ODB 数据库 ORM 框架详解 | 极客日志
C++
C++ ODB 数据库 ORM 框架详解 C++ ODB 是一个对象关系映射(ORM)框架,用于将 C++ 数据结构与数据库表进行映射。 ODB 的安装配置流程,涵盖 build2、odb-compiler 及 MySQL 环境搭建。内容包含 ODB 常用指令、类型映射规则、类接口定义及实际增删改查代码示例,帮助开发者理解如何在 C++ 项目中集成 ODB 进行数据库操作。
人间过客 发布于 2026/3/15 更新于 2026/5/1 12 浏览1.介绍
ODB 框架 :数据库 ORM 框架 --> 对象关系映射框架
形象理解 :将数据结构与数据库表进行关系映射 ,通过数据结构的操作实现数据库中数据操作
通过 ODB 框架实现 MySQL 数据库的关系映射操作
2.安装
1.安装 build2
因为 build2 安装时,可能会版本更新,因此注意,先从 build2 官网查看 安装步骤
如果安装过程中,因为网络问题超时失败,可以尝试:将超时时间设置的更长一些
sh build2-install-0.17.0.sh --timeout 1800
2.安装 odb-compiler
~/workspace$ sudo apt-get install gcc-13-plugin-dev
~/workspace$ mkdir odb-build && cd odb-build
~/workspace/odb-build$ bpkg create -d odb-gcc-N cc \
config.cxx=g++ \
config.cc.coptions=-O3 \
config.bin.rpath=/usr/lib \
config.install.root=/usr/ \
config.install.sudo=sudo
~/workspace/odb-build$ cd odb-gcc-N
~/workspace/odb-build/odb-gcc-N$ bpkg build odb@https://pkg.cppget.org/1/beta
~/workspace/odb-build/odb-gcc-N$ bpkg test odb
~/workspace/odb-build/odb-gcc-N$ bpkg install odb
~/workspace/odb-build/odb-gcc-N$ odb --version
$ sudo echo 'export PATH=${PATH}:/usr/local/bin' >> ~/.bashrc
$ export PATH=${PATH} :/usr/local/bin
$ odb --version
3.安装 ODB 运行时库
~/workspace/odb-build/odb-gcc-N$ cd ..
~/workspace/odb-build$ bpkg create -d libodb-gcc-N cc \
config.cxx=g++ \
config.cc.coptions=-O3 \
config.install.root=/usr/ \
config.install.sudo=sudo
~/workspace/odb-build$ cd libodb-gcc-N
~/workspace/odb-build/libodb-gcc-N$ bpkg add https://pkg.cppget.org/1/beta
~/workspace/odb-build/libodb-gcc-N$ bpkg fetch
~/workspace/odb-build/libodb-gcc-N$ bpkg build libodb
~/workspace/odb-build/libodb-gcc-N$ bpkg build libodb-mysql
4.安装 MySQL 和客户端开发包 sudo systemctl restart mysql
sudo systemctl enable mysql
sudo cat /etc/mysql/debian.cnf
sudo mysql -u debian-sys-maint -p
Enter password:
mysql> ALTER USER 'root' @'localhost' IDENTIFIED WITH mysql_native_password BY 'PASSWORD' ;
mysql> FLUSH PRIVILEGES;
mysql> quit
配置 MySQL :sudo vim /etc/my.cnf 或者 /etc/mysql/my.cnf,有哪个修改哪个
[client]
default-character-set =utf8
[mysql]
default-character-set =utf8
[mysqld]
character-set-server =utf8
bind-address = 0.0 .0.0
sudo apt install mysql-server
sudo apt install -y libmysqlclient-dev
5.安装 boost profile 库
6.总体操作 bpkg fetch
bpkg status
bpkg uninstall - all --recursive
bpkg build --upgrade --recursive
bpkg install --all --recursive
bpkg uninstall - all --recursive
bpkg install --all --recursive
7.测试样例 c++ -o test test.cpp person odb.cxx -lodb-mysql -lodb -lodb-boost
#include <string>
#include <memory>
#include <cstdlib>
#include <iostream>
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include "person.hpp"
#include "person-odb.hxx"
int main () {
std::shared_ptr<odb::core::database> db (new odb::mysql::database("root" , "SnowK8989" , "TestDB" , "127.0.0.1" , 0 , 0 , "utf8" )) ;
if (!db) return -1 ;
ptime p = boost::posix_time::second_clock::local_time ();
Person Die ("Die" , 18 , p) ;
Person SnowK ("SnowK" , 19 , p) ;
typedef odb::query<Person> query;
typedef odb::result<Person> result;
{
odb::core::transaction t (db->begin()) ;
size_t zid = db->persist (Die);
size_t wid = db->persist (SnowK);
t.commit ();
}
{
odb::core::transaction t (db->begin()) ;
result r (db->query<Person>()) ;
for (result::iterator i (r.begin ()); i != r.end (); ++i) {
std::cout << "Hello, " << i->name () << " " ;
std::cout << i->age () << " " << i->update () << std::endl;
}
t.commit ();
}
return 0 ;
}
$ odb -d mysql --generate-query --generate-schema --profile boost/date-time person.hpp
$ ls person.hpp person-odb.cxx person-odb.hxx person-odb.ixx person.sql
#pragma once
#include <string>
#include <cstddef>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <odb/core.hxx>
typedef boost::posix_time::ptime ptime;
#pragma db object
class Person {
public :
Person (const std::string &name, int age, const ptime &update) : _name(name), _age(age), _update(update) {}
void age (int val) { _age = val; }
int age () { return _age; }
void name (const std::string &val) { _name = val; }
std::string name () { return _name; }
void update (const ptime &update) { _update = update; }
std::string update () { return boost::posix_time::to_simple_string (_update); }
private :
friend class odb ::access;
Person () {}
#pragma db id auto
unsigned long _id;
unsigned short _age;
std::string _name;
#pragma db type("TIMESTAMP" ) not_null
boost::posix_time::ptime _update;
};
3.ODB 常见操作
1.ODB 类型映射
2.ODB 编程
1.指令
ODB(Open Database) 在数据元结构定义时,使用预处理器指令 (#pragma) 来提供元数据
这些元数据指示如何将 C++ 类型映射到数据库模式
这些 #pragma 指令是在 C++ 代码中使用的,它们不是 C++ 语言的一部分,而是特定于 ODB 编译器的扩展
常用 #pragma 指令
表的映射 :
#pragma db object:用于声明一个类是数据库对象
#pragma db table("table_name"):指定类映射到数据库中的表名
字段的映射 :
#pragma db id:标记类中的一个成员变量作为数据库表的主键
#pragma db column("column_name"):指定类成员映射到数据库表中的列名
#pragma db auto:指定成员变量的值在插入时自动生成
#pragma db type("type_name"):指定成员变量不应该被持久化到数据库中
#pragma db unique:指定成员变量或一组变量应该具有唯一性约束
#pragma db index("index_name"):指定成员变量应该被索引
#pragma db null:指定成员变量允许为空
#pragma db not_null:指定成员变量不允许为空
#pragma db default("default_value"):指定成员变量的默认值
查询相关 :
#pragma db view:用于声明一个类是一个数据库视图,而不是一个表
#pragma db query("query"):用于定义自定义的查询函数
其它 :
#pragma db session:用于声明一个全局或成员变量是数据库会话
#pragma db transient:指定成员变量不应该被持久化到数据库中
#pragma db convert("converter"):指定用于成员变量的自定义类型转换器
#pragma db pool("pool_name"):指定用于数据库连接的连接池
#pragma db trigger("trigger_name"):指定在插入、更新或删除操作时触发的触发器
2.示例 #pragma once
#include <string>
#include <cstddef>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <odb/nullable.hxx>
#include <odb/core.hxx>
#pragma db object
class Student {
public :
Student () {}
Student (unsigned long sn, const std::string &name, unsigned short age, unsigned long cid) : _sn(sn), _name(name), _age(age), _classes_id(cid) {}
void sn (unsigned long num) { _sn = num; }
unsigned long sn () { return _sn; }
void name (const std::string &name) { _name = name; }
std::string name () { return _name; }
void age (unsigned short num) { _age = num; }
odb::nullable<unsigned short > age () { return _age; }
void classes_id (unsigned long cid) { _classes_id = cid; }
unsigned long classes_id () { return _classes_id; }
private :
friend class odb ::access;
#pragma db id auto
unsigned long _id;
#pragma db unique
unsigned long _sn;
std::string _name;
odb::nullable<unsigned short > _age;
#pragma db index
unsigned long _classes_id;
};
#pragma db object
class Classes {
public :
Classes () {}
Classes (const std::string &name) : _name(name) {}
void name (const std::string &name) { _name = name; }
std::string name () { return _name; }
private :
friend class odb ::access;
#pragma db id auto
unsigned long _id;
std::string _name;
};
#pragma db view object(Student)\
object(Classes = classes : Student::_classes_id == classes::_id)\
query((?))
struct Classes_Student {
#pragma db column(Student::_id)
unsigned long id;
#pragma db column(Student::_sn)
unsigned long sn;
#pragma db column(Student::_name)
std::string name;
#pragma db column(Student::_age)
odb::nullable<unsigned short > age;
#pragma db column(classes::_name)
std::string classes_name;
};
#pragma db view query("select name from Student + (?)" )
struct All_Name {
std::string name;
};
4.类与接口 namespace odb {
namespace mysql {
class LIBODB_MYSQL_EXPORT new_connection_factory : public connection_pool_factory {
connection_pool_factory (std::size_t max_connections = 0 , std::size_t min_connections = 0 , bool ping = true );
};
}
class LIBODB_EXPORT database {
unsigned long long erase_query (const std::string&) ;
result<T> query (const std::string&) ;
result<T> query (const odb::query<T>&, bool cache = true ) ;
typename result<T>::pointer_type query_one (const odb::query<T>&) ;
};
class LIBODB_EXPORT transaction {
transaction (transaction_impl*, bool make_current = true );
void commit () ;
void rollback () ;
};
template <typename T>
class nullable {
typedef T value_type;
T& get () ;
const T& get () const ;
T* operator ->();
const T* operator ->() const ;
T& operator *();
const T* operator *() const ;
};
template <typename T>
class result : result_base<T, class_traits<T>::kind> {
result ();
result (const result& r);
iterator begin () ;
iterator end () ;
size_type size () ;
bool empty () ;
};
class LIBODB_EXPORT query_base {
explicit query_base (const std::string& native) ;
const clause_type& clause () ;
};
namespace mysql {
template <typename T>
class query : public query_base, public query_selector<T, id_mysql>::columns_type {
query (const std::string& q);
query (const query_base& q);
query (bool v);
};
}
template <typename T>
class query <T, mysql::query_base> : public mysql::query<T> {
query (bool v);
query (const std::string& q);
query (const mysql::query_base& q);
}
}
5.使用 #include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include <gflags/gflags.h>
#include "student.hpp"
#include "student-odb.hxx"
DEFINE_string (host, "127.0.0.1" , "Mysql 服务器地址" );
DEFINE_int32 (port, 0 , "Mysql 服务器端口" );
DEFINE_string (db, "TestDB" , "数据库默认库名称" );
DEFINE_string (user, "root" , "Mysql 用户名" );
DEFINE_string (pwd, "SnowK8989" , "Mysql 密码" );
DEFINE_string (cset, "utf8" , "Mysql 客户端字符集" );
DEFINE_int32 (max_pool, 3 , "Mysql 连接池最大连接数量" );
void Insert_Classes (odb::mysql::database& db) {
try {
odb::transaction trans (db.begin()) ;
Classes c1 ("Electronic 221" ) ;
Classes c2 ("Electronic 222" ) ;
db.persist (c1);
db.persist (c2);
trans.commit ();
} catch (const std::exception& e) {
std::cout << "插入数据出错:" << e.what () << std::endl;
}
}
void Insert_Student (odb::mysql::database &db) {
try {
odb::transaction trans (db.begin()) ;
Student s1 (1 , "张三" , 18 , 1 ) ;
Student s2 (2 , "李四" , 19 , 1 ) ;
Student s3 (3 , "王五" , 18 , 1 ) ;
Student s4 (4 , "赵六" , 15 , 2 ) ;
Student s5 (5 , "刘七" , 18 , 2 ) ;
Student s6 (6 , "孙八" , 23 , 2 ) ;
db.persist (s1);
db.persist (s2);
db.persist (s3);
db.persist (s4);
db.persist (s5);
db.persist (s6);
trans.commit ();
} catch (const std::exception &e) {
std::cout << "插入学生数据出错:" << e.what () << std::endl;
}
}
void Update_Student (odb::mysql::database &db, Student &stu) {
try {
odb::transaction trans (db.begin()) ;
db.update (stu);
trans.commit ();
} catch (const std::exception &e) {
std::cout << "更新学生数据出错:" << e.what () << std::endl;
}
}
Student Select_Student (odb::mysql::database &db) {
Student ret;
try {
odb::transaction trans (db.begin()) ;
odb::result<Student> r (db.query<Student>(odb::query<Student>::name == "张三" )) ;
if (r.size () != 1 ) {
std::cout << "数据量不对" << std::endl;
return Student ();
}
ret = *r.begin ();
trans.commit ();
} catch (const std::exception &e) {
std::cout << "更新学生数据出错:" << e.what () << std::endl;
}
return ret;
}
void Remove_Student (odb::mysql::database &db) {
try {
odb::transaction trans (db.begin()) ;
db.erase_query <Student>(odb::query<Student>::name == "李四" );
trans.commit ();
} catch (const std::exception &e) {
std::cout << "更新学生数据出错:" << e.what () << std::endl;
}
}
void Classes_Student (odb::mysql::database &db) {
try {
odb::transaction trans (db.begin()) ;
typedef odb::query<struct Classes_Student > query;
typedef odb::result<struct Classes_Student > result;
result r (db.query<struct Classes_Student>(query::classes::id == 1 )) ;
for (auto it = r.begin (); it != r.end (); ++it) {
std::cout << it->id << std::endl;
std::cout << it->sn << std::endl;
std::cout << it->name << std::endl;
std::cout << *it->age << std::endl;
std::cout << it->classes_name << std::endl;
}
trans.commit ();
} catch (const std::exception &e) {
std::cout << "更新学生数据出错:" << e.what () << std::endl;
}
}
void All_Student (odb::mysql::database &db) {
try {
odb::transaction trans (db.begin()) ;
typedef odb::query<Student> query;
typedef odb::result<All_Name> result;
result r (db.query<All_Name>(query::id == 1 )) ;
for (auto it = r.begin (); it != r.end (); ++it) {
std::cout << it->name << std::endl;
}
trans.commit ();
} catch (const std::exception &e) {
std::cout << "查询所有学生姓名数据出错:" << e.what () << std::endl;
}
}
int main (int argc, char * argv[]) {
google::ParseCommandLineFlags (&argc, &argv, true );
auto cpf = std::make_unique <odb::mysql::connection_pool_factory>(FLAGS_max_pool, 0 );
odb::mysql::database db (FLAGS_user, FLAGS_pwd, FLAGS_db, FLAGS_host, FLAGS_port, "" , FLAGS_cset, 0 , std::move(cpf)) ;
All_Student (db);
return 0 ;
}
#pragma once
#include <string>
#include <cstddef>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <odb/nullable.hxx>
#include <odb/core.hxx>
#pragma db object
class Student {
public :
Student () {}
Student (unsigned long sn, const std::string &name, unsigned short age, unsigned long cid) : _sn(sn), _name(name), _age(age), _classes_id(cid) {}
void sn (unsigned long num) { _sn = num; }
unsigned long sn () { return _sn; }
void name (const std::string &name) { _name = name; }
std::string name () { return _name; }
void age (unsigned short num) { _age = num; }
odb::nullable<unsigned short > age () { return _age; }
void classes_id (unsigned long cid) { _classes_id = cid; }
unsigned long classes_id () { return _classes_id; }
private :
friend class odb ::access;
#pragma db id auto
unsigned long _id;
#pragma db unique
unsigned long _sn;
std::string _name;
odb::nullable<unsigned short > _age;
#pragma db index
unsigned long _classes_id;
};
#pragma db object
class Classes {
public :
Classes () {}
Classes (const std::string &name) : _name(name) {}
void name (const std::string &name) { _name = name; }
std::string name () { return _name; }
private :
friend class odb ::access;
#pragma db id auto
unsigned long _id;
std::string _name;
};
#pragma db view object(Student)\
object(Classes = classes : Student::_classes_id == classes::_id)\
query((?))
struct Classes_Student {
#pragma db column(Student::_id)
unsigned long id;
#pragma db column(Student::_sn)
unsigned long sn;
#pragma db column(Student::_name)
std::string name;
#pragma db column(Student::_age)
odb::nullable<unsigned short > age;
#pragma db column(classes::_name)
std::string classes_name;
};
#pragma db view query("select name from Student" + (?))
struct All_Name {
std::string name;
};
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online