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

ODB-Mysql API接口(常用类与函数)

文章目录

  • ODB API接口
    • ODB与mysql的数据类型映射表
    • pragma 预处理
      • 核心 `#pragma` 指令分类与详解
        • 一、类级指令:定义类与数据库表的映射
        • 二、成员级指令:定义成员与表列的映射
        • 三、关系映射指令:定义类之间的关联
        • 四、其他常用指令
        • 五、查询相关的指令
      • ODB 指令的解析流程
    • ODB 编译命令的详细解析
      • 基本命令格式
      • 核心选项详解
        • 1. 指定目标数据库(必选)
        • 2. 生成查询支持(常用)
        • 3. 生成数据库 schema(表结构)
        • 4. 生成会话支持(事务管理)
        • 5. 控制生成文件的输出路径
        • 6. 包含路径和宏定义
        • 7. 其他常用选项
      • 完整示例:生成 MySQL 映射代码
    • odb核心命名空间和类
      • odb::schema_catalog
        • 核心功能概述表
        • 详细方法用法表格
          • 1. 模式创建方法
          • 2. 模式删除方法
          • 3. 迁移和检查方法
        • 完整使用案例
          • 案例1:完整的数据库初始化
          • 案例2:条件创建和增量更新
          • 案例3:版本管理和迁移
          • 案例4:多模式管理(高级用法)
          • 案例5:测试环境管理
      • 错误处理最佳实践
        • 错误处理模板
      • 配置和编译要求
        • ODB编译选项表
      • 编译命令示例
    • odb::mysql
      • 核心组件概述表
      • mysql::database 详细用法
        • 构造函数参数表
        • 连接选项参数表
      • 完整使用案例
        • 案例1:基础数据库连接
        • 案例2:连接池配置
        • 案例3:高级连接选项
        • 案例4:事务管理和错误处理
        • 案例5:批量操作和性能优化
      • 连接工厂类型对比表
        • 连接工厂使用示例
      • 异常处理详细表
        • 高级错误处理
      • 编译和链接要求
        • 编译命令示例
      • 依赖库说明表
    • odb::mysql::database
      • 构造函数参数详解表
      • 连接选项参数详解表
      • 核心方法功能表
        • 数据库操作方法
        • 连接管理方法
      • 完整使用案例
        • 案例1:基础数据库连接和操作
        • 案例2:连接池配置和高并发
        • 案例3:高级查询和事务管理
        • 案例4:调试和性能监控
        • 案例5:生产环境配置
    • odb::result 和 odb::query
      • odb::result 核心方法详解表
      • odb::query 查询构建操作符表
      • 完整使用案例
        • 案例1:基础查询操作
        • 案例2:结果集遍历和处理
        • 案例3:高级查询功能
        • 案例4:聚合查询和统计
        • 案例5:分页查询和性能优化
        • 案例6:动态查询构建
        • 案例7:结果集转换和数据处理
      • 性能优化提示表
      • 错误处理表
    • 复杂多表查询操作
      • 一、复合查询(多条件组合)
        • 1. 核心用法
        • 2. 案例:查询 “年龄 18-30 岁且姓名以‘张’开头的人”
      • 二、连接查询(多表关联)
        • 1. 前提:定义关联类
        • 2. 核心用法
        • 3. 案例:查询 “住在北京且年龄> 25 岁的人及其地址”
      • 三、高级用法:显式指定连接类型(左连接、右连接)
      • 四、注意事项
    • 老版本创建库
      • 一、方法 1:执行 ODB 工具生成的建表 SQL(推荐,类型安全)
        • 1. 用 ODB 工具生成建表 SQL
        • 2. 在代码中读取并执行 SQL 文件
      • 二、方法 2:手动拼接建表 SQL(无 ODB 工具时用)
        • 关键注意:

ODB API接口

ODB与mysql的数据类型映射表

在使用 ODB(如 CodeSynthesis ODB)与 MySQL 数据库映射时,C++ 数据类型与 MySQL 字段类型的映射遵循一定规则。以下是常见的 C++ 类型到 MySQL 类型的映射表,包含默认映射及可自定义的选项:

C++ 类型默认 MySQL 类型说明 / 可选 MySQL 类型
boolTINYINT(1)存储布尔值(0 或 1)
charTINYINT可指定 UNSIGNED(如 TINYINT UNSIGNED
signed charTINYINT有符号 8 位整数
unsigned charTINYINT UNSIGNED无符号 8 位整数
short / int16_tSMALLINT有符号 16 位整数,可选 SMALLINT UNSIGNED
unsigned shortSMALLINT UNSIGNED无符号 16 位整数
int / int32_tINT有符号 32 位整数,可选 INT UNSIGNED
unsigned intINT UNSIGNED无符号 32 位整数
longBIGINT取决于平台(通常 64 位),有符号 64 位整数,可选 BIGINT UNSIGNED
unsigned longBIGINT UNSIGNED无符号 64 位整数
long long / int64_tBIGINT有符号 64 位整数
unsigned long longBIGINT UNSIGNED无符号 64 位整数
floatFLOAT单精度浮点数(4 字节)
doubleDOUBLE双精度浮点数(8 字节)
long doubleDOUBLE通常映射为 DOUBLE(MySQL 不直接支持 long double,需自定义)
std::stringVARCHAR(255)可通过 #pragma db type("VARCHAR(n)") 自定义长度(如 VARCHAR(1024)),或指定 TEXT
std::wstringVARCHAR(255)宽字符串,默认使用 UTF-8 编码,可选 TEXTLONGTEXT
std::vector<char>BLOB二进制数据,可选 TINYBLOBMEDIUMBLOBLONGBLOB
std::vector<unsigned char>BLOB同上
std::tm(日期时间)DATETIME包含日期和时间(年 - 月 - 日 时:分: 秒),可选 DATE(仅日期)、TIME(仅时间)
boost::date_time::dateDATE仅日期(需引入 boost 库支持)
boost::date_time::ptimeDATETIME日期 + 时间(需引入 boost 库支持)

pragma 预处理

在 ODB(Object-Database Binding,如 CodeSynthesis ODB)中,预处理器指令 #pragma 是核心元数据载体,用于向 ODB 代码生成器传递 C++ 类型与数据库模式(表、列、关系等)的映射规则。这些 #pragma 指令不影响 C++ 编译器的正常编译(编译器会忽略未识别的 #pragma),但会被 ODB 专用工具(如 odb 编译器)解析,生成对应的数据库操作代码(如建表语句、对象序列化 / 反序列化逻辑)。

核心 #pragma 指令分类与详解

ODB 的 #pragma 指令按功能可分为 类级指令(控制类与表的映射)、成员级指令(控制成员与列的映射)、关系指令(控制类之间的关联)等,以下是最常用的指令解析:

一、类级指令:定义类与数据库表的映射

类级指令作用于整个类,声明类与数据库表的对应关系,是 ODB 映射的基础。

  1. #pragma db object

    • 功能:声明当前类是一个 “持久化对象”,对应数据库中的一张表。

    • 说明:只有标记此指令的类才会被 ODB 处理,生成对应的表结构和操作代码。

    • 示例:

      #pragma db object  // 该类映射到数据库表
      class User { ... };
      
  2. #pragma db table("table_name")

    • 功能:自定义类对应的数据库表名(默认表名为类名,通常小写)。

    • 示例:

      #pragma db object
      #pragma db table("sys_user")  // 映射到表 "sys_user",而非默认的 "user"
      class User { ... };
      
  3. #pragma db abstract

    • 功能:声明类为 “抽象类”,不生成对应的表,但可被其他类继承(用于抽取公共字段)。

    • 示例:

      #pragma db object abstract  // 抽象类,无对应表
      class Base {
      protected:std::string name_;
      };#pragma db object
      class Derived : public Base { ... };  // 继承 Base 的字段,生成包含 name_ 的表
      
  4. #pragma db polymorphic

    • 功能:声明类为 “多态类”(含虚函数),支持多态查询(如查询父类时返回所有子类对象)。
    • 说明:需配合继承使用,ODB 会生成额外的类型标识字段(如 type_id)区分子类。
二、成员级指令:定义成员与表列的映射

成员级指令作用于类的成员变量,控制其对应的数据库列的属性(名称、类型、约束等)。

  1. #pragma db id

    • 功能:指定成员为数据库表的主键(PRIMARY KEY)。

    • 说明:每个持久化类必须有且仅有一个主键(复合主键需特殊处理)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db id  // id_ 作为主键unsigned long id_;std::string name_;
      };
      
  2. #pragma db column("column_name")

    • 功能:自定义成员对应的数据库列名(默认列名为成员变量名)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db column("user_name")  // 映射到列 "user_name"std::string name_;
      };
      
  3. #pragma db type("db_type")

    • 功能:自定义成员对应的数据库字段类型(覆盖默认映射)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db type("VARCHAR(1000)")  // 自定义字符串长度为 1000std::string bio_;  // 默认映射为 VARCHAR(255),此处修改为 VARCHAR(1000)
      };
      
  4. #pragma db not_null

    • 功能:指定列不为空(NOT NULL 约束)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db not_null  // 列 "user_name" 不允许为 NULLstd::string name_;
      };
      
  5. #pragma db unique

    • 功能:指定列的值唯一(UNIQUE 约束)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db unique  // 用户名唯一std::string username_;
      };
      
  6. #pragma db default(value)

    • 功能:指定列的默认值(DEFAULT 约束)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db default("guest")  // 默认用户名为 "guest"std::string username_;#pragma db default(0)  // 默认年龄为 0int age_;
      };
      
  7. #pragma db index

    • 功能:为列创建索引(加速查询)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;#pragma db index  // 为 email 列创建索引std::string email_;
      };
      
三、关系映射指令:定义类之间的关联

用于描述多个类(表)之间的关系(如一对一、一对多、多对多),对应数据库的外键约束。

  1. #pragma db one(一对一关系)

    • 功能:声明当前类与另一个类为一对一关联(如 UserProfile)。

    • 示例:

      #pragma db object
      class Profile {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string bio_;
      };#pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string name_;#pragma db one  // User 与 Profile 一对一关联std::shared_ptr<Profile> profile_;  // 外键指向 Profile 的 id
      };
      
  2. #pragma db many(一对多关系)

    • 功能:声明当前类与另一个类为一对多关联(如 AuthorBook)。

    • 示例:

      #pragma db object
      class Book {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string title_;#pragma db not_null  // 外键不为空std::shared_ptr<Author> author_;  // 多对一:多个 Book 关联一个 Author
      };#pragma db object
      class Author {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string name_;#pragma db many  // 一对多:一个 Author 关联多个 Bookstd::vector<std::shared_ptr<Book>> books_;
      };
      
  3. #pragma db value_type(值类型映射)

    • 功能:声明自定义结构体为 “值类型”(非独立表,其成员作为主表的列)。

    • 示例:

      // 地址结构体(值类型,无独立表)
      #pragma db value_type
      struct Address {std::string street_;std::string city_;
      };#pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;Address addr_;  // 地址的成员(street_、city_)会作为 User 表的列
      };
      
四、其他常用指令
  1. #pragma db version

    • 功能:为类添加版本字段(用于乐观锁,避免并发更新冲突)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string name_;#pragma db version  // 自动添加版本列(如 "version"),更新时自动递增unsigned int version_;
      };
      
  2. #pragma db transient

    • 功能:标记成员为 “临时成员”,不映射到数据库列(仅在内存中存在)。

    • 示例:

      #pragma db object
      class User {
      private:friend class odb::access;#pragma db idunsigned long id_;std::string name_;#pragma db transient  // 不存储到数据库std::string temp_data_;
      };
      
五、查询相关的指令

这些指令用于辅助查询(如定义成员别名、索引加速查询等),确保 ODB 能正确解析查询条件中的类成员。

  1. #pragma db member(member).query_name("alias")
  • 功能:为类成员定义查询别名(在查询表达式中可使用别名代替成员名,避免命名冲突)。

  • 示例:

    #pragma db object
    class Person {
    private:friend class odb::access;#pragma db idunsigned long id_;#pragma db member(name_).query_name("username")  // 别名 "username"std::string name_;#pragma db member(age_).query_name("user_age")   // 别名 "user_age"int age_;
    };
    

    后续查询中可使用username代替name_:

    odb::query<Person>(odb::query<Person>::username == "Alice")
    
  1. #pragma db index(...)
  • 功能:为成员创建数据库索引,加速查询(尤其是频繁作为查询条件的字段)。

  • 示例:

    #pragma db object
    class Person {
    private:friend class odb::access;#pragma db idunsigned long id_;#pragma db index  // 为 name_ 建立索引,加速按名称查询std::string name_;#pragma db index("age_idx")  // 自定义索引名int age_;
    };
    
  1. #pragma db queryable
  • 功能:声明类成员可被查询(默认所有非 transient 成员均可查询,此指令主要用于显式标记或覆盖默认行为)。

ODB 指令的解析流程

  1. 代码编写:开发者在 C++ 类中添加 ODB #pragma 指令,定义映射规则。
  2. 代码生成:使用odb编译器(如odb --database mysql user.hxx)解析带指令的头文件,生成:
    • 数据库表结构脚本(CREATE TABLE 语句);
    • 对象与数据库之间的序列化 / 反序列化代码(如 user-odb.hxxuser-odb.cxx)。
  3. 编译运行:将生成的代码与业务代码一起编译,通过 ODB 运行时库操作数据库。

ODB 编译命令(即 odb 工具的使用指令)是将带有 ODB 元数据(#pragma 指令)的 C++ 代码转换为数据库映射代码(如建表语句、对象序列化逻辑)的核心步骤。odb 工具由 CodeSynthesis 提供,其命令格式和参数需根据目标数据库、代码生成需求进行配置。以下是

ODB 编译命令的详细解析

基本命令格式

odb [选项]... 源文件...
  • 源文件:包含 ODB 元数据的 C++ 头文件(如 person.hxx),odb 工具会解析这些文件生成映射代码。
  • 选项:控制代码生成的规则(如目标数据库类型、生成文件类型等)。

核心选项详解

1. 指定目标数据库(必选)

--database(缩写 -d):指定目标数据库类型,决定生成的 SQL 语法和映射逻辑(不同数据库的类型、约束语法有差异)。支持的数据库类型:mysqlsqlitepostgresqloraclemssql 等。

示例

odb -d mysql person.hxx  # 生成适配 MySQL 的代码
odb --database sqlite user.hxx  # 生成适配 SQLite 的代码
2. 生成查询支持(常用)

--generate-query(缩写 -q):生成查询相关的代码,支持通过 ODB 提供的查询语法(类似 SQL)查询对象。若需使用 db.query<Person>(...) 等查询操作,必须添加此选项。

示例

odb -d mysql -q person.hxx  # 生成 MySQL 代码并支持查询
3. 生成数据库 schema(表结构)

--generate-schema(缩写 -s):生成创建数据库表的 SQL 脚本(CREATE TABLE 语句)。生成的脚本默认包含在代码中,也可通过 --schema-format 指定输出格式。

示例

odb -d mysql -s person.hxx  # 生成建表 SQL 脚本

附加选项:

  • --schema-name <name>:指定生成的 schema 名称(如数据库名)。

  • --schema-format <format>:指定 SQL 脚本格式,可选embedded(嵌入代码,默认)、separate(单独生成.sql文件)。

    odb -d mysql -s --schema-format separate person.hxx  # 生成单独的 person.sql 文件
    
4. 生成会话支持(事务管理)

--generate-session(缩写 -e):生成会话(session)相关代码,用于管理对象缓存和事务上下文(多线程或复杂关系场景常用)。

示例

odb -d postgresql -e -q user.hxx  # 生成会话支持和查询代码
5. 控制生成文件的输出路径

--output-dir <dir>(缩写 -o):指定生成文件的输出目录(默认与源文件同目录)。

示例

odb -d mysql -o ./generated person.hxx  # 生成的代码放入 ./generated 目录
6. 包含路径和宏定义

与 C++ 编译器类似,odb 工具需要知道头文件路径和宏定义才能正确解析代码:

  • --include <dir>(缩写 -I):添加头文件搜索路径(如依赖的第三方库头文件)。
  • --define <macro>(缩写 -D):定义宏(如条件编译的宏)。

示例

odb -d mysql -I ./include -D DEBUG person.hxx  # 包含 ./include 路径,定义 DEBUG 宏
7. 其他常用选项
  • --hxx-suffix <suffix>:指定生成的头文件后缀(默认 .hxx),如 --hxx-suffix .h
  • --cxx-suffix <suffix>:指定生成的源文件后缀(默认 .cxx),如 --cxx-suffix .
  • --verbose(缩写 -v):输出详细的生成过程(调试时用)。
  • --help(缩写 -h):查看所有选项的帮助信息。

完整示例:生成 MySQL 映射代码

假设我们有一个 person.hxx 文件(带 ODB 元数据),需要生成:

  • 适配 MySQL 的代码;
  • 支持查询操作;
  • 单独的建表 SQL 脚本;
  • 输出到 ./odb-gen 目录。

命令如下:

odb -d mysql \-q \-s --schema-format separate \-o ./odb-gen \person.hxx

执行后会生成:

  • ./odb-gen/person-odb.hxx:映射头文件(声明序列化 / 反序列化接口);
  • ./odb-gen/person-odb.cxx:映射源文件(实现数据库操作逻辑);
  • ./odb-gen/person.sql:MySQL 建表脚本(CREATE TABLE person (...))。

odb核心命名空间和类

odb::schema_catalog

核心功能概述表
功能类别方法名称作用适用场景
模式创建create_schema()创建所有持久化类的数据库表初始化数据库
表创建create_table()创建特定类的数据库表增量添加表
模式删除drop_schema()删除所有持久化类的表清理测试数据
表删除drop_table()删除特定类的表删除单个表
模式迁移migrate_schema()升级数据库模式到新版本版本升级
存在性检查exists()检查表是否存在条件创建
详细方法用法表格
1. 模式创建方法
方法签名参数说明返回值异常
void create_schema(database&)数据库连接引用voidodb::exception
void create_schema(database&, const std::string& name)数据库连接,模式名voidodb::exception
void create_table(database&, const std::string& name = "")数据库连接,表名前缀voidodb::exception
2. 模式删除方法
方法签名参数说明返回值异常
void drop_schema(database&)数据库连接引用voidodb::exception
void drop_schema(database&, const std::string& name)数据库连接,模式名voidodb::exception
void drop_table(database&, const std::string& name = "")数据库连接,表名前缀voidodb::exception
3. 迁移和检查方法
方法签名参数说明返回值异常
void migrate_schema(database&, unsigned long long version)数据库连接,目标版本voidodb::exception
bool exists(database&, const std::string& name = "")数据库连接,表名是否存在odb::exception
unsigned long long version(database&, const std::string& name = "")数据库连接,模式名当前版本号odb::exception
完整使用案例
案例1:完整的数据库初始化
#include <odb/database.hxx>
#include <odb/transaction.hxx>
#include <odb/mysql/database.hxx>
#include <odb/schema-catalog.hxx>#include "person.hxx"
#include "department.hxx"
#include "employee.hxx"class DatabaseManager {
public:static void initializeDatabase(odb::database& db) {try {odb::transaction t(db.begin());// 删除现有模式(如果存在)if (odb::schema_catalog::exists(db)) {std::cout << "删除现有模式..." << std::endl;odb::schema_catalog::drop_schema(db);}// 创建新表结构std::cout << "创建数据库表..." << std::endl;odb::schema_catalog::create_schema(db);t.commit();std::cout << "数据库初始化成功!" << std::endl;} catch (const odb::exception& e) {std::cerr << "数据库初始化失败: " << e.what() << std::endl;throw;}}
};
案例2:条件创建和增量更新
void conditionalSchemaCreation(odb::database& db) {odb::transaction t(db.begin());// 检查Person表是否存在if (!odb::schema_catalog::exists<Person>(db)) {std::cout << "创建Person表..." << std::endl;odb::schema_catalog::create_table<Person>(db);}// 检查Department表是否存在if (!odb::schema_catalog::exists<Department>(db)) {std::cout << "创建Department表..." << std::endl;odb::schema_catalog::create_table<Department>(db);}t.commit();
}
案例3:版本管理和迁移
void schemaMigrationExample(odb::database& db) {try {// 获取当前模式版本unsigned long long current_version = odb::schema_catalog::version(db);std::cout << "当前数据库版本: " << current_version << std::endl;// 迁移到最新版本unsigned long long target_version = 2; // 假设目标版本是2if (current_version < target_version) {odb::transaction t(db.begin());odb::schema_catalog::migrate_schema(db, target_version);t.commit();std::cout << "数据库迁移到版本 " << target_version << " 成功" << std::endl;}} catch (const odb::exception& e) {std::cerr << "迁移失败: " << e.what() << std::endl;}
}
案例4:多模式管理(高级用法)
void multiSchemaExample(odb::mysql::database& db) {// 创建主业务表(默认模式){odb::transaction t(db.begin());odb::schema_catalog::create_schema(db, "main_schema");t.commit();}// 创建日志表(独立模式){odb::transaction t(db.begin());odb::schema_catalog::create_schema(db, "log_schema");t.commit();}
}
案例5:测试环境管理
class TestDatabaseManager {
public:static void setupTestDatabase(odb::database& db) {odb::transaction t(db.begin());// 清理测试环境odb::schema_catalog::drop_schema(db);// 创建测试表结构odb::schema_catalog::create_schema(db);// 插入测试数据insertTestData(db);t.commit();}static void cleanupTestDatabase(odb::database& db) {odb::transaction t(db.begin());odb::schema_catalog::drop_schema(db);t.commit();}private:static void insertTestData(odb::database& db) {// 插入测试数据Person p1("测试用户1", 25);Person p2("测试用户2", 30);db.persist(p1);db.persist(p2);}
};

错误处理最佳实践

错误处理模板
void safeSchemaOperation(odb::database& db) {try {odb::transaction t(db.begin());// 执行模式操作if (!odb::schema_catalog::exists(db)) {odb::schema_catalog::create_schema(db);}t.commit();} catch (const odb::schema_catalog_exception& e) {std::cerr << "模式操作异常: " << e.what() << std::endl;// 处理模式相关异常} catch (const odb::exception& e) {std::cerr << "ODB异常: " << e.what() << std::endl;// 处理通用ODB异常} catch (const std::exception& e) {std::cerr << "标准异常: " << e.what() << std::endl;// 处理其他异常}
}

配置和编译要求

ODB编译选项表
编译选项作用示例
--generate-schema生成模式创建代码odb -d mysql --generate-schema person.hxx
--schema-format模式文件格式--schema-format separate
--schema-name指定模式名称--schema-name myapp
--default-database默认数据库类型--default-database mysql

编译命令示例

# 生成包含模式支持的ODB代码
odb -d mysql --generate-schema --std c++11 \--schema-format separate \person.hxx department.hxx employee.hxx# 编译程序
g++ -std=c++11 -o app \main.  person-odb.cxx department-odb.cxx employee-odb.cxx \-lodb -lodb-mysql -lmysqlclient

odb::mysql

核心组件概述表

组件类别类名作用关键特性
数据库连接mysql::databaseMySQL数据库连接实现连接池、字符集、SSL支持
连接工厂connection_factory连接创建策略单连接、连接池
连接池connection_pool数据库连接池管理最小/最大连接数、健康检查
异常类型mysql::exceptionMySQL特定异常错误码、SQL状态

mysql::database 详细用法

构造函数参数表
参数顺序参数类型默认值说明
1const std::string& user-数据库用户名
2const std::string& password-数据库密码
3const std::string& database-数据库名称
4const std::string& host"localhost"主机地址
5unsigned int port0端口号(0表示默认)
6const std::string& socket""Unix socket路径
7const std::string& options""连接选项字符串
连接选项参数表
选项格式示例作用
字符集charset=编码charset=utf8mb4设置客户端字符集
SSL模式ssl_mode=模式ssl_mode=REQUIREDSSL连接模式
超时设置connect_timeout=秒connect_timeout=10连接超时时间
压缩compress=truecompress=true启用压缩协议
本地文件local_infile=1local_infile=1允许LOAD DATA LOCAL

完整使用案例

案例1:基础数据库连接
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include <odb/transaction.hxx>void basicConnectionExample() {try {// 基础连接参数odb::mysql::database db("test_user",      // 用户名"test_password",  // 密码  "test_db",        // 数据库名"localhost",      // 主机3306,            // 端口"",              // Unix socket"charset=utf8mb4" // 连接选项);std::cout << "MySQL数据库连接成功!" << std::endl;// 测试查询odb::transaction t(db.begin());auto result = db.query<int>("SELECT 1");t.commit();} catch (const odb::mysql::exception& e) {std::cerr << "MySQL错误: " << e.what() << " [代码: " << e.error_code() << "]" << std::endl;} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;}
}
案例2:连接池配置
#include <odb/mysql/connection.hxx>
#include <odb/mysql/connection-factory.hxx>void connectionPoolExample() {try {// 创建连接池工厂auto factory = std::make_shared<odb::mysql::connection_pool_factory>(10,  // 最大连接数2,   // 最小连接数true // 启用健康检查);// 使用连接池创建数据库实例odb::mysql::database db("user", "password", "database", "localhost", 3306,"", "charset=utf8mb4", factory);// 在多线程环境中使用#pragma omp parallel forfor (int i = 0; i < 10; ++i) {odb::transaction t(db.begin());// 每个线程使用独立的数据库连接db.execute("INSERT INTO logs (message) VALUES ('Thread: " + std::to_string(i) + "')");t.commit();}} catch (const odb::exception& e) {std::cerr << "连接池错误: " << e.what() << std::endl;}
}
案例3:高级连接选项
void advancedConnectionExample() {try {// 构建复杂连接选项std::string options = "charset=utf8mb4&""connect_timeout=10&""ssl_mode=REQUIRED&""compress=true&""auto_reconnect=1";odb::mysql::database db("app_user",           // 用户名"secure_password",    // 密码"production_db",      // 数据库名"db.cluster.example.com", // 主机3306,                 // 端口"",                   // socketoptions               // 连接选项);// 设置SQL跟踪器(调试用)db.tracer(std::make_shared<odb::stderr_tracer>());// 获取连接信息std::cout << "客户端版本: " << db.client_version() << std::endl;std::cout << "服务器版本: " << db.server_version() << std::endl;} catch (const odb::mysql::exception& e) {std::cerr << "MySQL连接错误 [" << e.error_code() << "]: " << e.what() << std::endl;}
}
案例4:事务管理和错误处理
class MySQLTransactionManager {
public:static bool transferMoney(odb::mysql::database& db, long from_account, long to_account, double amount) {odb::transaction t(db.begin());try {// 检查发送方余额double from_balance = db.query<double>("SELECT balance FROM accounts WHERE id = " + std::to_string(from_account)).begin()->get();if (from_balance < amount) {std::cerr << "余额不足" << std::endl;t.rollback();return false;}// 扣款db.execute("UPDATE accounts SET balance = balance - " + std::to_string(amount) + " WHERE id = " + std::to_string(from_account));// 存款db.execute("UPDATE accounts SET balance = balance + " + std::to_string(amount) + " WHERE id = " + to_string(to_account));// 记录交易db.execute("INSERT INTO transactions (from_acc, to_acc, amount) VALUES (" +std::to_string(from_account) + ", " +std::to_string(to_account) + ", " +std::to_string(amount) + ")");t.commit();std::cout << "转账成功: " << amount << std::endl;return true;} catch (const odb::mysql::exception& e) {std::cerr << "MySQL事务错误: " << e.what() << std::endl;t.rollback();return false;}}
};
案例5:批量操作和性能优化
void batchOperationsExample(odb::mysql::database& db) {odb::transaction t(db.begin());try {// 启用批量插入优化db.execute("SET autocommit=0");db.execute("SET unique_checks=0");db.execute("SET foreign_key_checks=0");// 批量插入数据for (int i = 0; i < 1000; ++i) {db.execute("INSERT INTO bulk_data (value, timestamp) VALUES (" +std::to_string(i) + ", NOW())");}// 恢复设置db.execute("SET foreign_key_checks=1");db.execute("SET unique_checks=1");t.commit();std::cout << "批量插入完成" << std::endl;} catch (const odb::exception& e) {std::cerr << "批量操作失败: " << e.what() << std::endl;t.rollback();}
}

连接工厂类型对比表

工厂类型类名特点适用场景
单连接工厂single_connection_factory每次返回同一连接单线程应用
新连接工厂new_connection_factory每次创建新连接简单多线程
连接池工厂connection_pool_factory连接池管理高并发生产环境
连接工厂使用示例
void connectionFactoryExamples() {// 1. 单连接工厂(默认)auto single_factory = std::make_shared<odb::mysql::single_connection_factory>();// 2. 新连接工厂auto new_factory = std::make_shared<odb::mysql::new_connection_factory>();// 3. 连接池工厂auto pool_factory = std::make_shared<odb::mysql::connection_pool_factory>(20,    // 最大连接数5,     // 最小连接数true,  // 启用ping检查60,    // 连接超时秒数300    // 连接最大空闲时间);// 使用连接池创建数据库odb::mysql::database db_with_pool("user", "pass", "db", "localhost", 3306, "", "", pool_factory);
}

异常处理详细表

异常类型触发条件处理方法
mysql::database_exception数据库操作错误检查SQL语法、权限
mysql::connection_exception连接相关错误检查网络、认证信息
mysql::timeout_exception操作超时调整超时设置、优化查询
mysql::deadlock_exception死锁检测重试机制、调整事务隔离级别
高级错误处理
void comprehensiveErrorHandling() {try {odb::mysql::database db("user", "pass", "db");// 数据库操作...} catch (const odb::mysql::deadlock_exception& e) {// 死锁处理:重试逻辑std::cerr << "检测到死锁,正在重试..." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));// 重试操作} catch (const odb::mysql::timeout_exception& e) {// 超时处理std::cerr << "操作超时: " << e.what() << std::endl;} catch (const odb::mysql::connection_exception& e) {// 连接异常处理std::cerr << "连接失败: " << e.what() << " [错误码: " << e.error_code() << "]" << std::endl;} catch (const odb::mysql::database_exception& e) {// 数据库操作异常std::cerr << "数据库错误: " << e.what() << " [SQL状态: " << e.sql_state() << "]" << std::endl;}
}

编译和链接要求

编译命令示例
# 编译ODB MySQL应用
g++ -std=c++11 -o mysql_app \main.  person-odb.cxx \-lodb -lodb-mysql -lmysqlclient \-I/usr/local/include/mysql \-L/usr/local/lib/mysql# 使用pkg-config(推荐)
g++ -std=c++11 -o mysql_app \main.  person-odb.cxx \$(pkg-config --cflags --libs libodb libodb-mysql mysqlclient)

依赖库说明表

库名称作用安装命令(Ubuntu)
libodbODB核心库apt-get install libodb-dev
libodb-mysqlMySQL数据库适配器apt-get install libodb-mysql-dev
libmysqlclientMySQL客户端库apt-get install libmysqlclient-dev

odb::mysql::database

构造函数参数详解表

参数位置参数类型默认值说明示例
1const std::string& user-数据库用户名"root"
2const std::string& password-数据库密码"password"
3const std::string& database-数据库名称"myapp_db"
4const std::string& host"localhost"主机地址"127.0.0.1"
5unsigned int port0端口号(0=默认3306)3306
6const std::string& socket""Unix socket路径"/var/run/mysqld/mysqld.sock"
7const std::string& options""连接选项字符串"charset=utf8mb4"
8connection_factory_ptr factorynullptr连接工厂指针连接池工厂

连接选项参数详解表

选项参数格式默认值说明示例
字符集charset=编码-客户端字符集charset=utf8mb4
SSL模式ssl_mode=模式-SSL连接模式ssl_mode=REQUIRED
连接超时connect_timeout=秒-连接超时时间connect_timeout=10
压缩compress=布尔值false启用压缩协议compress=true
自动重连auto_reconnect=布尔值false自动重新连接auto_reconnect=1
本地数据local_infile=布尔值false允许LOAD DATAlocal_infile=1
初始化命令init_command=SQL-连接后执行命令init_command=SET NAMES utf8mb4

核心方法功能表

数据库操作方法
方法名参数返回值说明
persist(T& object)对象引用void插入对象到数据库
find<T>(const id_type& id)主键值shared_ptr<T>根据主键查找对象
update(const T& object)对象常量引用void更新数据库中的对象
erase(const T& object)对象常量引用void删除数据库中的对象
erase_query<T>(const query<T>&)查询条件unsigned long long条件删除,返回影响行数
query<T>(const query<T>&)查询条件result<T>执行查询返回结果集
query_value<T>(const query<T>&)查询条件T查询单个值
execute(const std::string& sql)SQL语句void执行原始SQL语句
连接管理方法
方法名参数返回值说明
tracer(tracer_ptr t)跟踪器指针void设置SQL查询跟踪器
connection_factory()connection_factory_ptr获取连接工厂
client_version()unsigned long获取客户端版本
server_version()unsigned long获取服务器版本

完整使用案例

案例1:基础数据库连接和操作
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include <odb/transaction.hxx>
#include <iostream>void basicDatabaseOperations() {try {// 创建数据库连接odb::mysql::database db("app_user",           // 用户名"secure_password",    // 密码"my_application",     // 数据库名"localhost",          // 主机3306,                // 端口"",                  // Unix socket"charset=utf8mb4&connect_timeout=10" // 选项);std::cout << "数据库连接成功!" << std::endl;std::cout << "MySQL服务器版本: " << db.server_version() << std::endl;// 开启事务odb::transaction t(db.begin());// 执行原始SQLdb.execute("CREATE TABLE IF NOT EXISTS test_table (id INT PRIMARY KEY, name VARCHAR(50))");// 插入数据db.execute("INSERT INTO test_table VALUES (1, '测试数据')");t.commit();std::cout << "操作完成!" << std::endl;} catch (const odb::mysql::exception& e) {std::cerr << "MySQL错误 [" << e.error_code() << "]: " << e.what() << std::endl;} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;}
}
案例2:连接池配置和高并发
#include <odb/mysql/connection-factory.hxx>
#include <odb/mysql/database.hxx>
#include <thread>
#include <vector>class DatabaseService {
private:odb::mysql::database db_;public:DatabaseService() : db_("user", "password", "db", "localhost", 3306, "", "charset=utf8mb4",std::make_shared<odb::mysql::connection_pool_factory>(20, 5, true)) {}void concurrentOperations() {std::vector<std::thread> threads;// 创建10个线程并发操作for (int i = 0; i < 10; ++i) {threads.emplace_back([this, i]() {try {odb::transaction t(db_.begin());// 每个线程插入数据db_.execute("INSERT INTO concurrent_log (thread_id, message) VALUES (" +std::to_string(i) + ", '线程消息')");t.commit();std::cout << "线程 " << i << " 完成操作" << std::endl;} catch (const std::exception& e) {std::cerr << "线程 " << i << " 错误: " << e.what() << std::endl;}});}// 等待所有线程完成for (auto& thread : threads) {thread.join();}}
};
案例3:高级查询和事务管理
#include <odb/query.hxx>
#include <odb/result.hxx>class AdvancedDatabaseOperations {odb::mysql::database& db_;public:AdvancedDatabaseOperations(odb::mysql::database& db) : db_(db) {}// 复杂事务操作bool transferFunds(long from_account, long to_account, double amount) {odb::transaction t(db_.begin());try {// 检查余额double balance = db_.query_value<double>(odb::query<double>::value.in(db_.query<double>("SELECT balance FROM accounts WHERE id = " + std::to_string(from_account))));if (balance < amount) {std::cerr << "余额不足" << std::endl;t.rollback();return false;}// 执行转账db_.execute("UPDATE accounts SET balance = balance - " + std::to_string(amount) + " WHERE id = " + std::to_string(from_account));db_.execute("UPDATE accounts SET balance = balance + " + std::to_string(amount) + " WHERE id = " + std::to_string(to_account));t.commit();std::cout << "转账成功: " << amount << std::endl;return true;} catch (const odb::exception& e) {std::cerr << "转账失败: " << e.what() << std::endl;t.rollback();return false;}}// 批量操作void batchInsertUsers(const std::vector<std::pair<std::string, int>>& users) {odb::transaction t(db_.begin());try {// 优化批量插入性能db_.execute("SET autocommit=0");db_.execute("SET unique_checks=0");for (const auto& user : users) {db_.execute("INSERT INTO users (name, age) VALUES ('" + user.first + "', " + std::to_string(user.second) + ")");}db_.execute("SET unique_checks=1");t.commit();std::cout << "批量插入 " << users.size() << " 条记录完成" << std::endl;} catch (const std::exception& e) {std::cerr << "批量插入失败: " << e.what() << std::endl;t.rollback();}}
};
案例4:调试和性能监控
#include <odb/tracer.hxx>class DebugTracer : public odb::tracer {
public:void execute(odb::connection&, const char* statement) override {std::cout << "[SQL执行] " << statement << std::endl;}void execute(odb::connection&, const std::string& statement) override {std::cout << "[SQL执行] " << statement << std::endl;}void prepare(odb::connection&, const char* statement) override {std::cout << "[SQL准备] " << statement << std::endl;}
};void debugDatabaseOperations() {// 创建带调试功能的数据库连接odb::mysql::database db("user", "password", "test_db", "localhost", 3306, "", "charset=utf8mb4");// 设置SQL跟踪器auto tracer = std::make_shared<DebugTracer>();db.tracer(tracer);// 执行操作,所有SQL都会被记录odb::transaction t(db.begin());db.execute("SELECT * FROM users WHERE age > 18");db.execute("UPDATE users SET status = 'active'");t.commit();
}
案例5:生产环境配置
class ProductionDatabaseConfig {
public:static odb::mysql::database createProductionDatabase() {// 生产环境连接选项std::string options = "charset=utf8mb4&""connect_timeout=10&""ssl_mode=REQUIRED&""auto_reconnect=1&""init_command=SET SESSION sql_mode='STRICT_TRANS_TABLES'";// 使用连接池auto connection_pool = std::make_shared<odb::mysql::connection_pool_factory>(50,     // 最大连接数10,     // 最小连接数true,   // 启用健康检查30,     // 连接超时(秒)300     // 最大空闲时间(秒));return odb::mysql::database("prod_user",           // 用户名"strong_password",     // 密码"production_db",       // 数据库名"db-cluster.example.com", // 主机3306,                  // 端口"",                    // socketoptions,               // 连接选项connection_pool        // 连接池);}static void initializeDatabase(odb::mysql::database& db) {try {odb::transaction t(db.begin());// 设置数据库会话参数db.execute("SET NAMES utf8mb4");db.execute("SET time_zone='+08:00'");db.execute("SET sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'");t.commit();std::cout << "生产数据库初始化完成" << std::endl;} catch (const std::exception& e) {std::cerr << "数据库初始化失败: " << e.what() << std::endl;throw;}}
};

odb::result 和 odb::query

odb::result 核心方法详解表

方法名返回值类型参数说明时间复杂度
begin()iterator返回指向第一个元素的迭代器O(1)
end()iterator返回尾后迭代器O(1)
size()size_type返回结果集大小O(1)
empty()bool检查结果集是否为空O(1)
front()pointer_type返回第一个元素的指针O(1)
first()pointer_type返回第一个元素的指针O(1)
count()size_type返回结果数量O(1)

odb::query 查询构建操作符表

操作符语法对应SQL说明
==query<T>::age == 25age = 25等于比较
!=query<T>::age != 25age != 25不等于比较
<query<T>::age < 25age < 25小于比较
<=query<T>::age <= 25age <= 25小于等于
>query<T>::age > 25age > 25大于比较
>=query<T>::age >= 25age >= 25大于等于
&&q1 && q2condition1 AND condition2逻辑与
```q1
!!query<T>::deletedNOT deleted逻辑非

完整使用案例

案例1:基础查询操作
#include <odb/database.hxx>
#include <odb/query.hxx>
#include <odb/result.hxx>
#include <iostream>#pragma db object
class Person {
public:Person() {}Person(const std::string& name, int age, double salary) : name_(name), age_(age), salary_(salary) {}// Gettersconst std::string& name() const { return name_; }int age() const { return age_; }double salary() const { return salary_; }private:friend class odb::access;#pragma db id autounsigned long id_;std::string name_;int age_;double salary_;
};void basicQueryOperations(odb::database& db) {try {odb::transaction t(db.begin());// 1. 简单等值查询odb::result<Person> result1 = db.query<Person>(odb::query<Person>::name == "张三");std::cout << "找到 " << result1.size() << " 个名为张三的人" << std::endl;// 2. 范围查询odb::result<Person> result2 = db.query<Person>(odb::query<Person>::age >= 18 && odb::query<Person>::age <= 65);// 3. 多条件组合查询odb::result<Person> result3 = db.query<Person>((odb::query<Person>::age > 25 || odb::query<Person>::salary > 5000) &&odb::query<Person>::name != "测试用户");t.commit();} catch (const std::exception& e) {std::cerr << "查询错误: " << e.what() << std::endl;}
}
案例2:结果集遍历和处理
void resultSetProcessing(odb::database& db) {odb::transaction t(db.begin());// 执行查询odb::result<Person> people = db.query<Person>(odb::query<Person>::age > 20);std::cout << "查询结果数量: " << people.size() << std::endl;// 方法1: 使用迭代器遍历std::cout << "\n=== 迭代器遍历 ===" << std::endl;for (odb::result<Person>::iterator it = people.begin(); it != people.end(); ++it) {std::cout << "ID: " << it->id() << ", 姓名: " << it->name() << ", 年龄: " << it->age() << std::endl;}// 方法2: 基于范围的for循环 (C++11)std::cout << "\n=== 范围for循环 ===" << std::endl;for (const Person& person : people) {std::cout << "姓名: " << person.name() << ", 年龄: " << person.age() << ", 薪资: " << person.salary() << std::endl;}// 方法3: 使用front()获取第一个结果if (!people.empty()) {auto first_person = people.front();std::cout << "\n第一个结果: " << first_person->name() << std::endl;}t.commit();
}
案例3:高级查询功能
void advancedQueryFeatures(odb::database& db) {odb::transaction t(db.begin());try {// 1. LIKE 模糊查询odb::result<Person> like_result = db.query<Person>(odb::query<Person>::name.like("张%"));std::cout << "姓张的人数: " << like_result.size() << std::endl;// 2. IN 查询std::vector<int> ages = {20, 25, 30, 35};odb::result<Person> in_result = db.query<Person>(odb::query<Person>::age.in(ages.begin(), ages.end()));std::cout << "年龄在指定范围内的人数: " << in_result.size() << std::endl;// 3. BETWEEN 范围查询odb::result<Person> between_result = db.query<Person>(odb::query<Person>::salary.between(3000.0, 8000.0));std::cout << "薪资在3000-8000之间的人数: " << between_result.size() << std::endl;// 4. IS NULL 查询odb::result<Person> null_result = db.query<Person>(odb::query<Person>::name.is_null());std::cout << "姓名为空的人数: " << null_result.size() << std::endl;// 5. 排序查询odb::result<Person> sorted_result = db.query<Person>(odb::query<Person>::age > 18,"ORDER BY" + odb::query<Person>::age + "DESC," + odb::query<Person>::salary + "ASC");t.commit();} catch (const std::exception& e) {std::cerr << "高级查询错误: " << e.what() << std::endl;}
}
案例4:聚合查询和统计
#include <odb/query-dyn.hxx>void aggregateQueries(odb::database& db) {odb::transaction t(db.begin());try {// 1. 计数查询std::size_t count = db.query_value<std::size_t>("COUNT(*)",odb::query<Person>::age > 25);std::cout << "年龄大于25岁的人数: " << count << std::endl;// 2. 平均值查询double avg_salary = db.query_value<double>("AVG(" + odb::query<Person>::salary + ")",odb::query<Person>::age.between(25, 40));std::cout << "25-40岁平均薪资: " << avg_salary << std::endl;// 3. 最大值查询int max_age = db.query_value<int>("MAX(" + odb::query<Person>::age + ")",odb::query<Person>::salary > 0);std::cout << "最大年龄: " << max_age << std::endl;// 4. 分组查询struct AgeGroup {int age_group;std::size_t count;double avg_salary;#pragma db objectAgeGroup() {}};odb::result<AgeGroup> group_result = db.query<AgeGroup>("SELECT FLOOR(age/10)*10 AS age_group, ""COUNT(*) AS count, ""AVG(salary) AS avg_salary ""FROM Person ""GROUP BY FLOOR(age/10)*10 ""ORDER BY age_group");for (const AgeGroup& group : group_result) {std::cout << "年龄组 " << group.age_group << "+: " << group.count << "人, 平均薪资: " << group.avg_salary << std::endl;}t.commit();} catch (const std::exception& e) {std::cerr << "聚合查询错误: " << e.what() << std::endl;}
}
案例5:分页查询和性能优化
class PaginatedQuery {odb::database& db_;std::size_t page_size_;public:PaginatedQuery(odb::database& db, std::size_t page_size = 10) : db_(db), page_size_(page_size) {}void queryWithPagination(const std::string& search_name = "") {odb::transaction t(db_.begin());try {// 构建基础查询条件auto base_query = odb::query<Person>::age > 18;if (!search_name.empty()) {base_query = base_query && odb::query<Person>::name.like("%" + search_name + "%");}// 获取总记录数std::size_t total_count = db_.query_value<std::size_t>("COUNT(*)",base_query);std::size_t total_pages = (total_count + page_size_ - 1) / page_size_;std::cout << "总记录数: " << total_count << ", 总页数: " << total_pages << std::endl;// 分页查询for (std::size_t page = 0; page < total_pages; ++page) {std::size_t offset = page * page_size_;odb::result<Person> page_result = db_.query<Person>(base_query,"LIMIT " + std::to_string(page_size_) + " OFFSET " + std::to_string(offset));std::cout << "\n=== 第 " << (page + 1) << " 页 ===" << std::endl;for (const Person& person : page_result) {std::cout << "姓名: " << person.name() << ", 年龄: " << person.age() << std::endl;}}t.commit();} catch (const std::exception& e) {std::cerr << "分页查询错误: " << e.what() << std::endl;}}
};
案例6:动态查询构建
#include <odb/query-dyn.hxx>class DynamicQueryBuilder {
public:static odb::query<Person> buildDynamicQuery(const std::string& name_filter = "",int min_age = 0,int max_age = 0,double min_salary = 0.0) {odb::query<Person> query;// 动态添加姓名条件if (!name_filter.empty()) {query = query && odb::query<Person>::name.like("%" + name_filter + "%");}// 动态添加年龄条件if (min_age > 0) {query = query && odb::query<Person>::age >= min_age;}if (max_age > 0 && max_age >= min_age) {query = query && odb::query<Person>::age <= max_age;}// 动态添加薪资条件if (min_salary > 0.0) {query = query && odb::query<Person>::salary >= min_salary;}return query;}
};void dynamicQueryExample(odb::database& db) {odb::transaction t(db.begin());// 构建动态查询auto dynamic_query = DynamicQueryBuilder::buildDynamicQuery("张",    // 姓名包含"张"25,      // 最小年龄2540,      // 最大年龄405000.0   // 最低薪资5000);// 执行动态查询odb::result<Person> result = db.query<Person>(dynamic_query);std::cout << "动态查询结果数量: " << result.size() << std::endl;for (const Person& person : result) {std::cout << person.name() << " - " << person.age() << "岁" << std::endl;}t.commit();
}
案例7:结果集转换和数据处理
#include <vector>
#include <algorithm>class ResultProcessor {
public:// 将result转换为vectorstatic std::vector<Person> toVector(odb::result<Person>& result) {std::vector<Person> vec;vec.reserve(result.size());for (const Person& person : result) {vec.push_back(person);}return vec;}// 处理结果集并返回统计信息static void analyzeResult(odb::result<Person>& result) {if (result.empty()) {std::cout << "结果集为空" << std::endl;return;}int min_age = std::numeric_limits<int>::max();int max_age = std::numeric_limits<int>::min();double total_salary = 0.0;std::size_t count = 0;for (const Person& person : result) {min_age = std::min(min_age, person.age());max_age = std::max(max_age, person.age());total_salary += person.salary();count++;}std::cout << "统计信息:" << std::endl;std::cout << "  记录数: " << count << std::endl;std::cout << "  年龄范围: " << min_age << " - " << max_age << std::endl;std::cout << "  平均薪资: " << (total_salary / count) << std::endl;}
};

性能优化提示表

优化技巧说明示例
使用索引为查询条件字段创建索引#pragma db index
限制结果集使用LIMIT避免返回大量数据query + "LIMIT 100"
选择合适字段只查询需要的字段使用特定字段而非SELECT *
批量处理对大结果集进行分页处理使用OFFSET和LIMIT
连接池使用连接池减少连接开销connection_pool_factory

错误处理表

错误类型原因解决方法
odb::result_not_unique期望单个结果但找到多个使用query_one()或检查查询条件
odb::object_not_persistent操作未持久化的对象先调用persist()
odb::database_exception数据库操作错误检查SQL语法和权限

复杂多表查询操作

在 ODB 中,复合查询(多条件组合)和连接查询(多表关联)是处理复杂数据查询的核心能力。以下结合具体案例说明其用法,假设存在两个持久化类:Person(人员)和 Address(地址),其中 PersonAddress 是一对一关联(一个人对应一个地址)。

一、复合查询(多条件组合)

复合查询通过逻辑运算符(&&||!)组合多个条件,实现复杂筛选。

1. 核心用法
  • 使用 odb::query<T> 模板类,通过类成员(如 age_name_)构建条件;
  • 支持 &&(与)、||(或)、!(非)组合条件;
  • 支持 LIKE(模糊匹配)、IN(包含)、BETWEEN(范围)等辅助操作符。
2. 案例:查询 “年龄 18-30 岁且姓名以‘张’开头的人”
#include <odb/query.hxx>
#include "person.hxx"
#include "person-odb.hxx"// 复合查询示例
void complex_query(odb::mysql::database& db) {odb::transaction t(db.begin());// 构建查询条件:年龄在18-30之间(BETWEEN)且姓名以"张"开头(LIKE)odb::query<Person> q((odb::query<Person>::age_ BETWEEN 18 AND 30) &&  // 年龄范围(odb::query<Person>::name_ LIKE "张%")          // 姓名模糊匹配);// 执行查询odb::result<Person> res = db.query<Person>(q);// 遍历结果std::cout << "符合条件的人员:\n";for (const auto& p : res) {std::cout << "ID: " << p.id() << ", 姓名: " << p.name() << ", 年龄: " << p.age() << "\n";}t.commit();
}
  • 生成的 SQL 类似:

    SELECT * FROM Person WHERE age BETWEEN 18 AND 30 AND name LIKE '张%'
    

二、连接查询(多表关联)

连接查询用于关联多个表的数据(如 PersonAddress),需通过类之间的关联关系(如 #pragma db one 声明一对一)实现。

1. 前提:定义关联类

首先定义 PersonAddress 类,并声明关联关系:

// address.hxx
#pragma db object
class Address {
public:#pragma db id autounsigned long id_;std::string city_;  // 城市std::string street_; // 街道// ... 其他成员
};// person.hxx
#pragma db object
class Person {
public:#pragma db id autounsigned long id_;std::string name_;int age_;// 一对一关联:一个人对应一个地址#pragma db onestd::shared_ptr<Address> addr_;  // 关联到Address// ... 其他成员
};

通过 ODB 工具生成映射文件(person-odb.hxxaddress-odb.hxx)后,即可进行连接查询。

2. 核心用法
  • 通过关联成员(如 Person::addr_)访问关联表的字段;
  • 使用 odb::query 中的 join 逻辑(ODB 自动生成关联条件);
  • 支持跨表条件组合(如筛选 “住在北京且年龄> 25 岁的人”)。
3. 案例:查询 “住在北京且年龄> 25 岁的人及其地址”
#include "person.hxx"
#include "address.hxx"
#include "person-odb.hxx"
#include "address-odb.hxx"// 连接查询示例
void join_query(odb::mysql::database& db) {odb::transaction t(db.begin());// 构建连接查询条件:// 1. 人员年龄>25岁(Person表)// 2. 关联的地址城市为"北京"(Address表)odb::query<Person> q((odb::query<Person>::age_ > 25) && (odb::query<Person>::addr_->city_ == "北京")  // 跨表访问Address的city_);// 执行查询(结果包含Person及其关联的Address)odb::result<Person> res = db.query<Person>(q);// 遍历结果,同时访问关联的地址信息std::cout << "符合条件的人员及地址:\n";for (const auto& p : res) {std::cout << "姓名: " << p.name() << ", 年龄: " << p.age()<< ", 地址: " << p.addr_->city_ << p.addr_->street_ << "\n";}t.commit();
}
  • 生成的 SQL 类似(自动关联Person.addr_id和Address.id):

    SELECT * FROM Person JOIN Address ON Person.addr_id = Address.id WHERE Person.age > 25 AND Address.city = '北京'
    

三、高级用法:显式指定连接类型(左连接、右连接)

ODB 默认为内连接(INNER JOIN),若需左连接(LEFT JOIN),可通过原生 SQL 片段拼接实现:

// 左连接查询:所有人员,即使没有地址也会被查询出来
odb::query<Person> q = odb::query<Person>() + "LEFT JOIN Address ON Person.addr_id = Address.id ""WHERE Person.age < 30";odb::result<Person> res = db.query<Person>(q);

四、注意事项

  1. 关联关系必须声明:连接查询依赖类中的关联注解(#pragma db one/#pragma db many),否则 ODB 无法生成关联条件。
  2. 性能优化:关联查询可能触发多表扫描,建议为关联字段(如 Person.addr_id)创建索引(#pragma db index)。
  3. 类型安全:ODB 通过模板检查跨表字段访问的合法性(如 addr_->city_ 必须是 Address 类的成员),编译期报错避免拼写错误。

老版本创建库

在 ODB 老版本中,若没有 odb::schema_catalog::create_table<Person>(db) 方法,可通过以下两种兼容方式创建表,核心是直接执行建表 SQL 语句(绕开 ODB 高版本的 schema 管理接口):

一、方法 1:执行 ODB 工具生成的建表 SQL(推荐,类型安全)

ODB 工具(odb 命令)可根据持久化类生成对应的 CREATE TABLE 语句,老版本也支持。步骤如下:

1. 用 ODB 工具生成建表 SQL

在终端执行以下命令,根据你的 Person 类头文件(如 person.hxx)生成建表 SQL:

# 语法:odb -d 数据库类型 -s 持久化类头文件
odb -d mysql -s person.hxx
  • 参数说明:

    • -d mysql:指定数据库类型(生成 MySQL 语法的 SQL);

    • -s--generate-schema):生成建表 SQL 脚本;

    • 执行后会生成person.sql文件,内容为CREATE TABLE语句(如:

      CREATE TABLE `Person` (`id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(255) NOT NULL,`age` INT NOT NULL
      ) ENGINE=InnoDB;
      
2. 在代码中读取并执行 SQL 文件

通过 C++ 读取 person.sql 内容,调用 database::execute 执行建表语句(老版本 ODB 均支持 execute 方法):

#include <fstream>
#include <string>
#include <odb/mysql/database.hxx>
#include <odb/transaction.hxx>
#include "person.hxx"
#include "person-odb.hxx"// 读取 SQL 文件内容
std::string read_sql(const std::string& path) {std::ifstream file(path);if (!file) throw std::runtime_error("无法打开 SQL 文件: " + path);return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
}// 创建表(老版本 ODB 兼容)
void create_person_table(odb::mysql::database& db) {odb::transaction t(db.begin());try {// 读取 ODB 生成的建表 SQLstd::string sql = read_sql("person.sql");// 执行 SQL 创建表db.execute(sql);std::cout << "Person 表创建成功!\n";t.commit();} catch (const std::exception& e) {std::cerr << "创建表失败: " << e.what() << "\n";t.rollback();}
}// 主函数中调用
int main() {try {// 连接数据库(假设已存在,或通过之前的方法创建)odb::mysql::database db("user", "password", "testdb");// 创建表create_person_table(db);} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << "\n";}return 0;
}

二、方法 2:手动拼接建表 SQL(无 ODB 工具时用)

若无法使用 ODB 工具生成 SQL,可根据 Person 类的字段手动编写 CREATE TABLE 语句,直接通过 execute 执行:

void create_person_table_manual(odb::mysql::database& db) {odb::transaction t(db.begin());try {// 手动拼接建表 SQL(字段需与 Person 类完全匹配)std::string sql = "CREATE TABLE IF NOT EXISTS `Person` (""`id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, "  // 自增主键"`name` VARCHAR(255) NOT NULL, "  // 对应 std::string name_"`age` INT NOT NULL"              // 对应 int age_") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";  // 字符集避免中文乱码db.execute(sql);  // 执行手动编写的 SQLstd::cout << "Person 表创建成功(手动方式)!\n";t.commit();} catch (const std::exception& e) {std::cerr << "创建表失败: " << e.what() << "\n";t.rollback();}
}
关键注意:
  • 表名、字段名需与 person-odb.hxx 中定义的映射一致(如 Person 类映射的表名是 Person,字段是 idnameage);
  • 字段类型需匹配(如 id 对应 BIGINT UNSIGNEDname 对应 VARCHARTEXT);
  • IF NOT EXISTS 避免重复创建时抛错(MySQL 错误码 1050)。
http://www.dtcms.com/a/491134.html

相关文章:

  • AI视频修复技术入门:从Sora水印谈起,我们如何“抹去”未来影像的瑕疵?
  • 佛山中小企业网站制作濮阳网络
  • 招生网站建设方案烟台网站建设首推企汇互联见效付款
  • 第12章:Spring AI Alibaba 可观测性—深入追踪AI应用的“黑盒”行为与性能瓶颈
  • 策略模式:让算法选择像点菜一样简单
  • 10.16 作业
  • 上海企业工商查询拼多多seo是什么意思
  • 国外人像摄影网站国内建站平台
  • 详细的Linux系统更新yum源的教程
  • 余姚做网站设计的淄博网站制作价格低
  • HolmesGPT 正式上线 丨 KubeSphere 助力云原生智能排障新体验
  • 【开题答辩过程】以《基于微信小程序教学评价平台的设计与实现》为例,不会开题答辩的可以进来看看
  • 淘宝式网站建设国外注册品牌 建设网站
  • 邵阳网站建设设计哈尔滨制作网站工作室
  • 管理中心理学问:人为什么要学习?
  • 长沙网站托管公司排名wordpress相册幻灯片
  • ps网站怎么做超链接海南百度首页广告
  • seo网站建设哪家专业wordpress建好本地站怎么上传
  • JVM 之 volatile可见性、禁止指令重排序的JVM实现
  • 荣耀手机2025年10月发布的新品Magic8比起Magic7,在硬件、性能、价格等上有什么区别,有什么优势
  • YOLO V1 和 V2笔记
  • C++ 创建一个窗口采用GDI的方式绘制文字
  • 谷歌网站推广费用建网站域名注册
  • python 网站开发 普及消防证怎么考取需要什么条件
  • 网络层次划分-网络层
  • 做响应式网站应该注意什么问题有自己的域名怎么建设网站
  • ClickHouse 数据更新策略深度解析:突变操作与最佳实践
  • 餐饮商城网站建设网站备案幕布要求
  • Prometheus监控部署
  • php ajax网站开发典型实例 pdfwordpress账号邮箱