ODB 是一个开源、跨平台、跨数据库的对象关系映射(ORM)系统,用于将 C++ 对象持久化到关系数据库中。它支持多种数据库,如 MySQL、SQLite、PostgreSQL、Oracle 和微软 SQL Server。ODB 的主要功能是将 C++ 类和数据库表之间进行自动映射,从而简化数据库操作。
功能:
类型安全:ODB 提供类型安全的映射操作,避免了直接使用 SQL 语句时可能发生的类型转换错误。
自动生成 SQL 代码:ODB 会根据 C++ 类和类成员的定义自动生成 SQL 查询语句。
支持复杂数据关系:ODB 支持对象之间复杂的关系映射,如一对多、多对多等关系,并且能够自动管理外键、级联操作等。
支持继承和多态:ODB 支持 C++ 类继承和多态,可以将继承层次结构中的类映射到数据库表。
#注意这里的 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
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
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
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
sudo systemctl restart mysql
sudo systemctl enable mysql
bpkg build libodb-boost
bpkg install --all --recursive
student.hxx
#pragma once
#include
#include // std::size_t
#include
#include
#include
#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 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 auto
unsigned long _id;
#pragma db unique
unsigned long _sn;
std::string _name;
odb::nullable _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 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
main.cc
#include
#include
#include "student.hxx"
#include "student-odb.hxx"
#include
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 query;
typedef odb::result result;
result r(db.query(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 query;
db.erase_query(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 query;
typedef odb::result result;
result r(db.query(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 query;
typedef odb::result result;
result r(db.query(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 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.cxx
g++ -o $@ $^ -std=c++17 -lodb -lodb-boost -lodb-mysql -lgflags