当前位置: 首页 > news >正文

ODB 的安装及使用

介绍

ODB 是一个开源、跨平台、跨数据库的对象关系映射(ORM)系统,用于将 C++ 对象持久化到关系数据库中。它支持多种数据库,如 MySQL、SQLite、PostgreSQL、Oracle 和微软 SQL Server。ODB 的主要功能是将 C++ 类和数据库表之间进行自动映射,从而简化数据库操作。

功能:

  • 类型安全:ODB 提供类型安全的映射操作,避免了直接使用 SQL 语句时可能发生的类型转换错误。

  • 自动生成 SQL 代码:ODB 会根据 C++ 类和类成员的定义自动生成 SQL 查询语句。

  • 支持复杂数据关系:ODB 支持对象之间复杂的关系映射,如一对多、多对多等关系,并且能够自动管理外键、级联操作等。

  • 支持继承和多态:ODB 支持 C++ 类继承和多态,可以将继承层次结构中的类映射到数据库表。

安装

安装 build2

因为 build2 安装时,有可能会版本更新,从 16 变成 17 ,或从 17 18 ,因此注意,先从 build2 官网查看安装步骤。安装步骤:https://build2.org/install.xhtml#unix

安装 odb-compiler

#注意这里的 gcc-11 需要根据你自己版本而定
sudo apt-get install gcc-11-plugin-dev
mkdir odb-build && cd 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
cd odb-gcc-N
bpkg build odb@https://pkg.cppget.org/1/beta
bpkg test odb
bpkg install odb
odb --version

安装 ODB 运行时库

cd ..
bpkg create -d libodb-gcc-N cc config.cxx=g++ config.cc.coptions=-O3 config.install.root=/usr/ config.install.sudo=sudo
cd libodb-gcc-N
bpkg add https://pkg.cppget.org/1/beta
bpkg fetch
bpkg build libodb
bpkg build libodb-mysql

安装 mysql 和客户端开发包

sudo apt install mysql-server
sudo apt install -y libmysqlclient-dev

配置 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
修改 root 用户密码
dev@bite:~$ sudo cat /etc/mysql/debian.cnf
# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host = localhost
user = debian-sys-maint
password = UWcn9vY0NkrbJMRC
socket = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host = localhost
user = debian-sys-maint
password = UWcn9vY0NkrbJMRC
socket = /var/run/mysqld/mysqld.sock
dev@bite:~$ sudo mysql -u debian-sys-maint -p
Enter password: #这里输入上边第 6 行看到的密码
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH 
mysql_native_password BY 'xxxxxx';
Query OK, 0 rows affected (0.01 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
mysql> quit
重启 mysql ,并设置开机启动
sudo systemctl restart mysql
sudo systemctl enable mysql

安装 boost profile

bpkg build libodb-boost
bpkg install --all --recursive

ODB 常见操作介绍

ODB 类型映射

ODB 编程

ODB Open Database )在数据元结构定义时,使用预处理器指令( #pragma )来提供元数据,这些元数据指示如何将 C++ 类型映射到数据库模式。这些 #pragma 指令是在 C++ 代码中使用的,它们不是 C++ 语言的一部分,而是特定于 ODB 编译器的扩展。以下是 ODB 中常用的一些 #pragma 指令:
  • #pragma db object: 用于声明一个类是数据库对象,即这个类将映射到数据库中的一个表。
  • #pragma db table("table_name"): 指定类映射到数据库中的表名。如果不指定,则默认使用类名。
  • #pragma db id: 标记类中的一个成员变量作为数据库表的主键。
  • #pragma db column("column_name"): 指定类成员映射到数据库表中的列名。如果不指定,则默认使用成员变量的名字。
  • #pragma db view: 用于声明一个类是一个数据库视图,而不是一个表。
  • #pragma db session: 用于声明一个全局或成员变量是数据库会话。
  • #pragma db query("query"): 用于定义自定义的查询函数。
  • #pragma db index("index_name"): 指定成员变量应该被索引。
  • #pragma db default("default_value"): 指定成员变量的默认值。
  • #pragma db unique: 指定成员变量或一组变量应该具有唯一性约束。
  • #pragma db not_null:  指定成员变量不允许为空。
  • #pragma db auto: 指定成员变量的值在插入时自动生成(例如,自动递增的主键)。
  • #pragma db transient: 指定成员变量不应该被持久化到数据库中。
  • #pragma db type("type_name"): 指定成员变量的数据库类型。
  • #pragma db convert("converter"): 指定用于成员变量的自定义类型转换器。
  • #pragma db pool("pool_name"): 指定用于数据库连接的连接池。
  • #pragma db trigger("trigger_name"): 指定在插入、更新或删除操作时触发的触发器。

使用案例

student.hxx

#pragma once
#include <string>
#include <cstddef> // std::size_t
#include <odb/nullable.hxx>
#include <odb/core.hxx>
#include <iostream>#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:// 将 odb::access 类作为 person 类的朋友。// 这是使数据库支持代码可访问默认构造函数和数据成员所必需的。// 如果类具有公共默认构造函数和公共数据成员或数据成员的公共访问器和修饰符,则不需要友元声明friend class odb::access;
#pragma db id autounsigned long _id;
#pragma db uniqueunsigned long _sn;std::string _name;odb::nullable<unsigned short> _age;
#pragma db indexunsigned 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 autounsigned 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;
};

编写好后,使用 odb 编译 student.hxx 文件,可以得到 student-odb.cxx,student-odb.hxx 和student-odb.ixx 三个文件,并且生成了 student.sql 文件。

odb -d mysql --std c++11 --generate-query --generate-schema --profile boost/date-time student.hxx

我们可以将生成的 student.sql 文件导入 mysql 中,从而自动构建好表,需要注意的是,要在student.sql 文件自己添加创建或者进入的库。

mysql -u root -p <student.sql

main.cc

#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include "student.hxx"
#include "student-odb.hxx"
#include <gflags/gflags.h>DEFINE_string(host, "127.0.0.1", "这是Mysql服务器地址");
DEFINE_int32(port, 3306, "这是Mysql服务器端口");
DEFINE_string(db, "TestDB", "数据库默认库名称");
DEFINE_string(user, "root", "这是Mysql用户名");
DEFINE_string(pswd, "2162627569", "这是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("一年级一班");Classes c2("一年级二班");db.persist(c1);db.persist(c2);// 5. 提交事务trans.commit();}catch (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);// 5. 提交事务trans.commit();}catch (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);// 5. 提交事务trans.commit();}catch (std::exception &e){std::cout << "更新学生数据出错:" << e.what() << std::endl;}
}
Student select_student(odb::mysql::database &db)
{Student res;try{// 获取事务对象开启事务odb::transaction trans(db.begin());typedef odb::query<Student> query;typedef odb::result<Student> result;result r(db.query<Student>(query::name == "张三"));if (r.size() != 1){std::cout << "数据量不对!\n";return Student();}res = *r.begin();// 5. 提交事务trans.commit();}catch (std::exception &e){std::cout << "更新学生数据出错:" << e.what() << std::endl;}return res;
}void remove_student(odb::mysql::database &db)
{try{// 获取事务对象开启事务odb::transaction trans(db.begin());typedef odb::query<Student> query;db.erase_query<Student>(query::classes_id == 2);// 5. 提交事务trans.commit();}catch (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;}// 5. 提交事务trans.commit();}catch (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<struct all_name> result;result r(db.query<struct all_name>(query::id == 1));for (auto it = r.begin(); it != r.end(); ++it){std::cout << it->name << std::endl;}// 5. 提交事务trans.commit();}catch (std::exception &e){std::cout << "查询所有学生姓名数据出错:" << e.what() << std::endl;}
}int main(int argc, char *argv[])
{google::ParseCommandLineFlags(&argc, &argv, true);// 1. 构造连接池工厂配置对象std::unique_ptr<odb::mysql::connection_pool_factory> cpf(new odb::mysql::connection_pool_factory(FLAGS_max_pool, 0));// 2. 构造数据库操作对象odb::mysql::database db(FLAGS_user, FLAGS_pswd, FLAGS_db,FLAGS_host, FLAGS_port, "", FLAGS_cset,0, std::move(cpf));// 4. 数据操作// insert_classes(db);// insert_student(db);//  auto stu = select_student(db);//  std::cout << stu.sn() << std::endl;//  std::cout << stu.name() << std::endl;//  if (stu.age()) std::cout << *stu.age() << std::endl;//  std::cout << stu.classes_id() << std::endl;// stu.age(15);// update_student(db, stu);// remove_student(db);// classes_student(db);all_student(db);return 0;
}

makefile

main:main.cc student-odb.cxxg++ -o $@ $^ -std=c++17 -lodb -lodb-boost -lodb-mysql -lgflags

相关文章:

  • 前端实现流式输出《后端返回Markdown格式文本,前端输出类似于打字的那种》
  • Systemd基础
  • qtc++ qdebug日志生成
  • 【gRPC】HTTP/2协议,HTTP/1.x中线头阻塞问题由来,及HTTP/2中的解决方案,RPC、Protobuf、HTTP/2 的关系及核心知识点汇总
  • 项目QT+ffmpeg+rtsp(一)——Qt的安装和rtsp的测试
  • python中集合的操作
  • Python 中的 typing.ClassVar 详解
  • 会议分享|高超声速流动测量技术研讨会精彩探析
  • windows下authas调试tomcat
  • 青少年ctf平台应急响应-应急响应1
  • 基于 nvitop+Prometheus+Grafana 的物理资源与 VLLM 引擎服务监控方案
  • 自学嵌入式 day19-数据结构 链表
  • 二水平设计的单次重复
  • 阳台光伏+储能:安科瑞智能计量仪表来助力
  • 学习海康VisionMaster之直方图工具
  • uniapp+vue3页面滚动加载数据
  • 现代计算机图形学Games101入门笔记(十四)
  • 电磁兼容性优化设计在汽车电子芯片中的实践
  • 在 VSCode 中运行 Vue.js 项目
  • 动态范围调整(SEF算法实现)
  • 朝鲜称将在各领域采取反制措施,应对美国敌对挑衅
  • 精品消费“精”在哪?多在体验上下功夫
  • 高途一季度净利润同比增长1108%: “与吴彦祖一起学英语”短时间内就实现了盈利
  • A股三大股指低收:汽车股领涨,大金融走弱,两市成交近1.1万亿元
  • 李强:把做强国内大循环作为推动经济行稳致远的战略之举
  • 伊朗最高领袖顾问:伊朗愿承诺永不制造核武,换取美解除制裁