009-sqlite-orm-sqlite数据库接口

ORM

  • O:Object/对象
  • R:Relational/关系型
  • M:Mapping/映射

一、建立映射

1759478842199

可能使用到的头文件:

#include<iostream>
#include<string>
#include<optional>
#include<exception>

#include<sqlite_orm/sqlite_orm.h>
namespace orm = sqlite_orm;

C++类定义:

struct FamilyMember {
    int id = -1; //唯一标识,自增

    std::string role; //角色:爷爷、奶奶……,不可重复
    std::optional<std::string> tel; //电话号码,可能没有

    std::string birthday; //出生日期,在表中不可为空
    std::string avatar = "0.png"; //头像文件名,默认为 0.png
    bool is_admin = false; //是否为管理员,默认为false
};

创建表格:

auto create_storage(std::string const &db_file) {
    return orm::make_storage(db_file,
         orm::make_table("family_member",
         orm::make_column("id", &FamilyMember::id,orm::primary_key().autoincrement()),
         orm::make_column("role", &FamilyMember::role, orm::unique()),
         orm::make_column("tel", &FamilyMember::tel, orm::null()),
         orm::make_column("birthday", &FamilyMember::birthday, orm::not_null()),
         orm::make_column("avatar", &FamilyMember::avatar, orm::default_value("0.png")),
         orm::make_column("is_admin", &FamilyMember::is_admin,orm::default_value(false))
        )
    );
}

插入初始数据:

using Storage = decltype(create_storage(""));

void insert_members(Storage &storage) {
    FamilyMember members[] = {
        {.role = "爸爸", .tel = "13902290392", .birthday = "1979-2-1"},
        {.role = "妈妈", .tel = "17120385678", .birthday = "1978-5-20", .is_admin = true},
        {.role = "大宝", .birthday = "2000-2-12", .avatar = "rabbit.png"},
        {.role = "二宝", .birthday = "2011-12-11", .avatar = "baby.png"},
        {.role = "二大爷", .birthday = "1979-2-1", .avatar = "robot.png"}

    };

    for (auto &member: members) {
        member.id = storage.insert(member);
    }

    std::cout << "原始数据已插入" << std::endl;
    for (auto const &member: members) {
        std::cout << storage.dump(member) << std::endl;
    }
}

函数调用:

int main() {
    auto storage = create_storage(":memory:");
    storage.sync_schema();

    try {
        insert_members(storage);
    } catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
    }
}

运行结果:

原始数据已插入
{ id : '1', role : '爸爸', tel : '13902290392', birthday : '1979-2-1', avatar : '0.png', is_admin : '0' }
{ id : '2', role : '妈妈', tel : '17120385678', birthday : '1978-5-20', avatar : '0.png', is_admin : '1' }
{ id : '3', role : '大宝', tel : 'NULL', birthday : '2000-2-12', avatar : 'rabbit.png', is_admin : '0' }
{ id : '4', role : '二宝', tel : 'NULL', birthday : '2011-12-11', avatar : 'baby.png', is_admin : '0' }
{ id : '5', role : '二大爷', tel : 'NULL', birthday : '1979-2-1', avatar : 'robot.png', is_admin : '0' }

1. C++ sqlite_orm 库中 make_storage 函数详解

make_storage是 C++ 的 sqlite_orm库中的核心函数,用于创建数据库存储对象并定义表结构。以下是详细解析:

基本语法

#include <sqlite_orm/sqlite_orm.h>
using namespace sqlite_orm;

auto storage = make_storage(
    "path/to/database.db",  // 数据库文件路径
    // 表定义...
);

核心功能

  1. 数据库连接
    • 第一个参数指定 SQLite 数据库文件路径(如 “db.sqlite”)
    • 若文件不存在,会自动创建
    • 支持内存数据库::memory:或空字符串
  2. 表结构定义
    • 使用 make_table 定义表
    • 每列格式:make_column("列名", &结构体::成员, 约束...)

列类型与约束:

类型说明示例
integer整型make_column(“id”, &User::id)
text字符串make_column(“name”, &User::name)
real浮点数make_column(“price”, &Product::price)
blob二进制数据make_column(“data”, &Data::blob)
约束说明示例
primary_key()主键make_column(“id”, &User::id).primary_key()
autoincrement()自增(需搭配主键)make_column(“id”, &User::id).primary_key().autoincrement()
unique()唯一约束make_column(“email”, &User::email).unique()
default(value)默认值make_column(“age”, &User::age).default_value(18)
not_null()非空约束make_column(“name”, &User::name).not_null()

完整示例

#include <sqlite_orm/sqlite_orm.h>
using namespace sqlite_orm;

// 定义数据结构
struct User {
    int id;
    std::string name;
    std::string email;
    int age;
};

struct Post {
    int id;
    int userId;
    std::string content;
};

// 创建存储对象
auto storage = make_storage(
    "test.db",
    make_table("users",
        make_column("id", &User::id, primary_key().autoincrement()),
        make_column("name", &User::name, not_null()),
        make_column("email", &User::email, unique().not_null()),
        make_column("age", &User::age, default_value(18))
    ),
    make_table("posts",
        make_column("id", &Post::id, primary_key().autoincrement()),
        make_column("user_id", &Post::userId, not_null()),
        make_column("content", &Post::content),
        foreign_key(&Post::userId).references(&User::id)
    )
);

// 同步表结构
storage.sync_schema();

高级用法

  1. 外键约束:
    make_table("posts",
    make_column("user_id", &Post::userId),
    foreign_key(&Post::userId).references(&User::id)
    );
  2. 自定义表名:
    make_table("custom_table_name", ...)
  3. 索引支持:
    make_column("email", &User::email).unique().index("idx_email")
  4. 多数据库连接:
    auto storage1 = make_storage("db1.sqlite", ...);
    auto storage2 = make_storage("db2.sqlite", ...);

生成的 storage 对象功能

常用功能:

// 插入数据
User user{0, "John", "john@example.com", 30};
int insertedId = storage.insert(user);

// 查询数据
auto users = storage.get_all<User>();
auto john = storage.get<User>(insertedId);

// 更新数据
john.age = 31;
storage.update(john);

// 删除数据
storage.remove<User>(insertedId);

// 复杂查询
auto adults = storage.get_all<User>(where(c(&User::age) >= 18));

事务支持:

storage.transaction([&] {
    storage.insert(user1);
    storage.insert(user2);
    return true; // 提交事务
});

注意事项

  • 同步表结构:
      storage.sync_schema(); // 创建或更新表结构
      storage.sync_schema(true); // 保留已有数据
  • 类型安全:
    • C++ 结构体必须与表定义匹配
    • 成员变量类型必须与列类型兼容
  • 性能优化:
    • 使用预编译语句提高性能
    • 批量操作使用事务
  • 线程安全:
    • 默认非线程安全
    • 多线程环境需要外部同步

2.storage.sync_schema()详解

storage.sync_schema()是 sqlite_orm库中用于同步数据库模式的核心函数,它会根据代码中定义的表结构自动创建或更新数据库中的实际表结构。

主要作用

  • 创建新表:如果数据库中没有代码中定义的表,会自动创建
  • 添加新列:如果表中缺少代码中定义的列,会自动添加
  • 更新列定义:修改列类型或约束(有限制)
  • 删除列:默认不会删除数据库中多余列(安全设计)
  • 重建表:当需要重大修改时自动重建表结构

参数详解

  1. 无参数版本(默认行为)

     storage.sync_schema();
    • 保留现有数据
    • 不删除多余列
    • 安全模式(推荐日常使用)
  2. 带参数版本

     storage.sync_schema(true);   // 保留数据
     storage.sync_schema(false);  // 删除所有数据重建表
  3. 高级控制(C++20 起支持)

     storage.sync_schema(
         sqlite_orm::preserve,   // 保留数据
         sqlite_orm::drop_table  // 删除多余表
     );

同步行为详解

不同场景下的处理方式:

场景处理方式注意事项
新表创建新表完全按照代码定义创建
缺少列添加新列需满足 SQLite 的 ALTER TABLE ADD COLUMN限制
多余列保留(默认)可通过参数配置删除
列类型变更尝试修改仅支持部分类型转换
约束变更重建表需要数据迁移
主键变更重建表数据会保留
表重命名视为新表旧表不会被删除

重要注意事项

  1. 列删除限制
    // 默认不会删除数据库中的多余列
    // 需要显式指定:
    storage.sync_schema(sqlite_orm::drop_extra_columns);
  2. 数据类型变更限制
    • 支持:TEXT → INTEGER(如果内容可转换)
    • 不支持:BLOB → TEXT(需要手动处理)
  3. 约束变更处理
    • 添加 UNIQUE/NOT NULL 约束可能失败(如果现有数据违反约束)
    • 移除约束需要重建表
  4. 外键处理
// 同步前禁用外键约束
storage.pragma.foreign_keys = false;
storage.sync_schema();
storage.pragma.foreign_keys = true;

完整工作流程

当调用 sync_schema() 时:

  1. 检查数据库中的当前模式
  2. 与代码定义的模式比较差异
  3. 按顺序执行变更:
    -- 1. 创建新表
    CREATE TABLE ... 
    
    -- 2. 添加新列
    ALTER TABLE ... ADD COLUMN ...
    
    -- 3. 重建需要修改的表
    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE ...;
    INSERT INTO ... SELECT ...;
    DROP TABLE ...;
    ALTER TABLE ... RENAME TO ...;
    COMMIT;
  4. 验证最终模式匹配

二、四种查询方式

  1. get:用主键,精准查询单个对象(变体get_pointer和get_optional)
  2. get_all:按条件,查询对象集合 -> std::vector<对象类型>
  3. iterate:按条件,查询并逐条获取对象
  4. select:按条件,查询记录中指定字段 -> std::tuple<…>(变体:仅查询一个字段 -> std::vector<…>)

其中,前三种为orm,第四种为非orm。

1.精准查询单一对象

//精准查询单一对象
void get_member(Storage &storage) {
    i_am_here;

    std::cout<<"请输入用户ID:";
    int id;
    std::cin>>id;

    auto member=storage.get<FamilyMember>(id);
    print(member);
}

运行结果:

[get_member]
请输入用户ID:1
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png

------------------------------------------------------------

2.精准查询单一对象变体1:使用optional

//精准查询单一对象变体1:使用optional
void get_member_optional(Storage &storage) {
    i_am_here;

    std::cout<<"请输入成员ID:";
    int id;
    std::cin>>id;
    auto member=storage.get_optional<FamilyMember>(id);

    if (member.has_value()) {
        print(*member);
    }
    else {
        std::cout<<"没有找到ID为"<<id<<"的对象"<<std::endl;
    }
}

3.精准查询单一对象变体2:使用智能指针

void get_member_pointer(Storage &storage) {
    i_am_here;

    std::cout<<"请输入成员ID:";
    int id;
    std::cin>>id;
    auto member=storage.get_pointer<FamilyMember>(id);

    if (member) {
        print(*member);
    }
    else {
        std::cout<<"没有找到ID为"<<id<<"的对象"<<std::endl;
    }
}

4.将查询对象转为对象集合

//将查询对象转为对象集合
void get_all_members(Storage &storage) {
    i_am_here;

    auto member=storage.get_all<FamilyMember>();
    for (auto const &m: member) {
        print(m);
    }
}
[get_all_members]
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------

5.迭代器查询

//通过迭代,获取每一行记录并转换为对象
void iterate_all_members(Storage &storage) {
    i_am_here;

    for (auto const &m: storage.iterate<FamilyMember>()) {
        print(m);
    }
}

6.通过select查询指定字段

//选择部分字段
void select_fields(Storage &storage) {
    i_am_here;

    auto rows=storage.select(orm::columns(&FamilyMember::id,&FamilyMember::role,&FamilyMember::tel));
    std::cout<<"ID\t角色\t电话号码\n";
    for (auto const &row: rows) {
        std::string tel=std::get<2>(row)?*std::get<2>(row):"~";
        std::cout<<std::get<0>(row)<<'\t'<<std::get<1>(row)<<'\t'<<tel<<std::endl;
    }
}
[select_fields]
ID	角色	电话号码
1	爸爸	13902290392
2	妈妈	17120385678
3	大宝	~
4	二宝	~
5	二大爷	~

7.通过select查询指定字段变体

//选择部分字段
void select_fields(Storage &storage) {
    i_am_here;

    auto rows=storage.select(orm::columns(&FamilyMember::id,&FamilyMember::role,&FamilyMember::tel));
    std::cout<<"ID\t角色\t电话号码\n";
    for (auto const &row: rows) {
        std::string tel=std::get<2>(row)?*std::get<2>(row):"~";
        std::cout<<std::get<0>(row)<<'\t'<<std::get<1>(row)<<'\t'<<tel<<std::endl;
    }
}
[select_one_field]
二大爷 二宝 大宝 妈妈 爸爸 

三、条件、排序、限行和偏移

1.条件/WHERE

1.1适用语句

  • get:该语句的固定参数为主键,因此无法使用条件
  • get_all
  • iterate
  • select
  • update:用于对特定主键的单一对象内容进行修改
  • update_all:用于修改满足条件的所有记录
  • remove:删除指定主键的单一对象
  • remove_all:删除满足条件的所有记录

1.2条件表达

  • 使用操作符:==!=<<=>>=
  • 使用函数:is_equalis_not_equalless_thanless_or_equalgreater_thangreater_or_equalis_nullis_not_nullinlikebetween

强调:在sql中,一个空的字符串 ""NULL是不同的,前者表示一个空字符串,后者表示没有值。

1.3注意事项

  1. 使用操作符:字段必须使用 sql_orm::c(成员偏移地址),明确转换为 sql_orm::column类型,注意,andornot也是c++操作符(替代运算符/alternative operators)
  2. 使用函数或者字段本身:直接使用字段偏移地址
  3. 双重语法限定:代码要遵守c++语法,而且生成的sql要满足sql的语法。

1.4示例比较

1

WHERE role = "爸爸"
// where(&FamilyMember::role == "爸爸"); /*错误用法*/
where(c(&FamilyMember::role) == "爸爸");
where(is_equal(&FamilyMember::role, "爸爸"));

2

WHERE tel IS NOT NULL
// where(c(&FamilyMember::tel) != nullptr); /*错误用法*/
where(is_not_null(&FamilyMember::tel));

3

WHERE is_admin = True
// where(c(&FamilyMember::is_admin)); /*错误用法*/
where(&FamilyMember::is_admin);
where(c(&FamilyMember::is_admin) == true);

4

WHERE is_admin = False
// where(not &FamilyMember::is_admin); /*错误用法*/
// where(! &FamilyMember::is_admin); /*错误用法*/
where(not c(&FamilyMember::is_admin));
where(! c(&FamilyMember::is_admin));
where(c(&FamilyMember::is_admin) == false);

5

WHERE is_admin AND tel IS NULL
// where(&FamilyMember::is_admin && is_null(&FamilyMember::tel)); /*错误用法*/
// where(&FamilyMember::is_admin and is_null(&FamilyMember::tel)); /*错误用法*/
where(c(&FamilyMember::is_admin) && is_null(&FamilyMember::tel));
where(c(&FamilyMember::is_admin) and is_null(&FamilyMember::tel));

1.5示例查询

// 带条件的get_all
void get_all_with_condition(Storage &storage) {
    i_am_here;

    auto conditions_desc = [](char const *desc) {
        std::cout << "\n> " << desc;
        line(30, '=');
    };
    auto print_list = [](auto const &members) {
        for (auto const &m: members) {
            print(m);
        }
    };

    {
        conditions_desc("管理员");
        auto admins = storage.get_all<FamilyMember>(
                orm::where(orm::c(&FamilyMember::is_admin) == true));
        print_list(admins);
    }

    {
        conditions_desc("普通用户");
        auto users = storage.get_all<FamilyMember>(
                orm::where(not orm::c(&FamilyMember::is_admin)));
    }

    {
        conditions_desc("年龄大于等于30岁的用户");
        auto elder30 = storage.get_all<FamilyMember>(orm::where(
                // 以下语句严重依赖sqlite特性
                orm::c(&FamilyMember::birthday) <= orm::datetime("now", "-30 years")));
        print_list(elder30);
    }

    {
        // 条件组合
        conditions_desc("年龄大于等于30岁的普通用户");
        auto elder30_not_admin = storage.get_all<FamilyMember>(
                orm::where((orm::c(&FamilyMember::birthday) <=
                            orm::datetime("now", "-30 years")) and
                           (not orm::c(&FamilyMember::is_admin))
                        )
                );

        print_list(elder30_not_admin);
    }

    {
        //LIKE 模糊查询
        conditions_desc("角色包含'宝'字的成员");
        auto members = storage.get_all<FamilyMember>(
                orm::where(orm::like(&FamilyMember::role, "%宝%"))
                );
        print_list(members);
    }

    {
        // IN 查询
        conditions_desc("指定ID集合的用户:");
        auto members = storage.get_all<FamilyMember>(
            orm::where(orm::in(&FamilyMember::id, {1, 4, 5}))
            );
        print_list(members);
    }
}
// 带条件的select
void select_fields_with_condition(Storage &storage) {
    i_am_here;

    auto member_base=storage.select(
        orm::columns(&FamilyMember::id,&FamilyMember::role,&FamilyMember::birthday),
        orm::where(not orm::c(&FamilyMember::is_admin))
    );
    std::cout<<"普通用户基本信息\n";
    for (auto const& m: member_base) {
        std::cout<<std::get<0>(m)<<"\t"<<std::get<1>(m)<<"\t"<<std::get<2>(m)<<std::endl;
    }
}

查询结果:

[select_fields_with_condition]
普通用户基本信息
1	爸爸	1979-2-1
3	大宝	2000-2-12
4	二宝	2011-12-11
5	二大爷	1979-2-1

2.排序、限制、偏移(ORDER,LIMIT,OFFSET)

2.1查询结果排序

  • order_by(成员偏移地址).asc():升序
  • order_by(成员偏移地址).desc():降序

演示程序:

//order查询结果集排序
void order_member(Storage &storage) {
    i_am_here;

    auto members=storage.get_all<FamilyMember>(
        orm::where(not orm::c(&FamilyMember::is_admin)),
        orm::order_by(&FamilyMember::birthday).desc()
        );

    std::cout<<"按生日降序排列:\n";
    for (auto const& m: members) {
        print(m);
    }
}

查询结果:

[order_member]
按生日降序排列:
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------

2.2查询条目行数限制与起始行偏移

  • limit(最大行数):仅限制结果集最大行数,零偏移
  • limit(最大行数,offset(起始行偏移)):限制结果集最大行数,并指定起始行偏移
  • limit(起始行,最大行数):限制结果集最大行数,并指定起始行偏移

演示程序:

//偏移与限行
void offset_limit(Storage &storage) {
    i_am_here;
    int offset=1;
    int limit=3;

    auto members=storage.get_all<FamilyMember>(
        orm::order_by(&FamilyMember::id).desc(),
        orm::limit(limit,orm::offset(offset))
        );

    std::cout<<"按ID降序排列,偏移"<<offset<<",限行"<<limit<<"条\n";
    for (auto const& m: members) {
        print(m);
    }
}

查询结果:

[offset_limit]
按ID降序排列,偏移1,限行3条
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------

四、插入、修改

1.insert的三种用法

  1. 插入整个对象(主键除外)
  2. 插入对象的指定字段(主键除外)
  3. 使用tuple插入指定字段

2.update的两种用法

  • update
  • update_all

3.remove(对应数据库的delete)

  • remove
  • remove_all

4.演示程序

//CRUD一条龙
void CRUD_operations(Storage &storage) {
    i_am_here;

    insert_method(storage,"爷爷","叔叔","阿姨");

    auto r=storage.get_all<FamilyMember>(orm::where(orm::c(&FamilyMember::role)=="爷爷"));
    assert(!r.empty());

    auto title=[](char const* title){std::cout<<'\n'<<title<<std::endl;};

    title("爷爷成员修改之前");
    auto g=r.front();
    print(r.front());

    g.avatar="雄鹰展翅.png";
    g.tel="15636562556";
    g.is_admin=true;

    storage.update<FamilyMember>(g);
    g=storage.get<FamilyMember>(g.id);
    title("爷爷成员修改之后");
    print(g);

    //批量
    storage.update_all(orm::set(orm::c(&FamilyMember::avatar)="admin.png"),orm::where(&FamilyMember::is_admin));

    title("批量修改之后");
    auto admins=storage.get_all<FamilyMember>(orm::where(&FamilyMember::is_admin));
    for (auto const& m: admins) {
        print(m);
    }

    //删除爷爷
    storage.remove<FamilyMember>(g.id);
    title("删除爷爷之后");

    r=storage.get_all<FamilyMember>(orm::where(orm::c(&FamilyMember::role)=="爷爷"));
    if (r.empty()) {
        std::cout<<"爷爷已删除"<<std::endl;
    }

    //删除叔叔、姑姑
    storage.remove_all<FamilyMember>(orm::where(orm::in(&FamilyMember::role,{"叔叔","姑姑"})));
    auto members=storage.get_all<FamilyMember>();
    for (auto const& m: members) {
        print(m);
    }

}

运行结果:

[CRUD_operations]

[insert_method]
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------
#7 叔叔    普通用户    	1982-06-04	~          	0.png
------------------------------------------------------------
#8 阿姨    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------

爷爷成员修改之前
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------

爷爷成员修改之后
#6 爷爷    管理员       	1950-10-01	15636562556	雄鹰展翅.png
------------------------------------------------------------

批量修改之后
#2 妈妈    管理员       	1978-5-20	17120385678	admin.png
------------------------------------------------------------
#6 爷爷    管理员       	1950-10-01	15636562556	admin.png
------------------------------------------------------------

删除爷爷之后
爷爷已删除
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	admin.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#8 阿姨    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------

五、事务/TRANSACTION

  • 作用:让连续的一段操作,要么全成功,要么全失败
  • 限制:仅对数据操作(CRUD)有效,对数据表或数据库结构的修改,不起作用
  • 要点:确实异常安全(包括来自数据库,或c++其他模块的异常)

1.事务的用法

1.1c风格

storage.begin_transaction();
//...
storage.rollback();
storage.commit();

1.2lambda风格

storage.transaction(
    [&]() mutable{
        //...
        return true;//成功,返回false,则回滚
    }
);

演示代码:

//事务 - 使用lambda
void transaction_lambda(Storage &storage,bool commit) {
    i_am_here;

    std::cout<<"示范事务"<<(commit?"提交":"回滚")<<"的效果"<<std::endl;

    bool committed=storage.transaction([&storage,commit]() {
        //事务内的操作
            insert_method(storage,"爷爷","叔叔","姑姑");
        return commit;
    });
    std::cout<<"事务"<<(committed?"提交":"回滚")<<"成功"<<std::endl;
    auto members=storage.get_all<FamilyMember>();
    for (auto const& m: members) {
        print(m);
    }
}

调用:

transaction_lambda(storage,false);
transaction_lambda(storage,true);

运行结果:

[transaction_lambda]
示范事务回滚的效果

[insert_method]
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------
#7 叔叔    普通用户    	1982-06-04	~          	0.png
------------------------------------------------------------
#8 姑姑    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------
事务回滚成功
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------

[transaction_lambda]
示范事务提交的效果

[insert_method]
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------
#7 叔叔    普通用户    	1982-06-04	~          	0.png
------------------------------------------------------------
#8 姑姑    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------
事务提交成功
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------
#7 叔叔    普通用户    	1982-06-04	~          	0.png
------------------------------------------------------------
#8 姑姑    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------

1.3哨兵风格

try{
    auto guard=storage.transaction_guard();
    //...
    guard.commit();
}catch(...){
    guard.rollback();
}

演示程序:

//事务 - 使用哨兵
void transaction_guard(Storage &storage) {
    i_am_here;

    try {
        auto guard=storage.transaction_guard();

        insert_method(storage,"爷爷","叔叔","姑姑");

        //故意重复插入奶奶
        storage.insert(orm::into<FamilyMember>(),
            orm::columns(&FamilyMember::role,&FamilyMember::birthday),
            orm::values(std::make_tuple("叔叔","1958-09-22")));

        guard.commit();
    }catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

    std::cout<<"> 事务回滚"<<std::endl;
    for (auto const& m:storage.iterate<FamilyMember>()) {
        print(m);
    }
}

运行结果:

[transaction_guard]

[insert_method]
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
#6 爷爷    普通用户    	1950-10-01	12556626696	grandpa.png
------------------------------------------------------------
#7 叔叔    普通用户    	1982-06-04	~          	0.png
------------------------------------------------------------
#8 姑姑    普通用户    	1985-12-12	123456789  	0.png
------------------------------------------------------------
> 事务回滚
#1 爸爸    普通用户    	1979-2-1	13902290392	0.png
------------------------------------------------------------
#2 妈妈    管理员       	1978-5-20	17120385678	0.png
------------------------------------------------------------
#3 大宝    普通用户    	2000-2-12	~          	rabbit.png
------------------------------------------------------------
#4 二宝    普通用户    	2011-12-11	~          	baby.png
------------------------------------------------------------
#5 二大爷 普通用户    	1979-2-1	~          	robot.png
------------------------------------------------------------
UNIQUE constraint failed: family_member.role: constraint failed