sqlite_orm学习笔记

git库

sqlite

从官网下载
https://www.sqlite.org/download.html
Source Code 里面下载
解压以后有四个文件:
Sqlite3基本需求使用sqlite3.h/.c ,其中shell.c可以编译出可以执行文件,另外一个头文件是用于扩展,外部接口导入。运行sqliteshell 可以用于数据库的简单测试:
	shell命令基本都是以.作为开始的,例如”.help” 查看帮助信息
	SQL语句是以”;”结束的,例如”create table student(id integer,name text,age integer,score integer); ”

sqlite_orm

git
https://github.com/fnc12/sqlite_orm
函数api
https://github.com/fnc12/sqlite_orm/wiki/storage_t::transaction使用前需要先准备好sqlite的文件
sqlite的文件:sqlite3.c sqlite3.h sqlite3ext.h
sqlite_orm只用到了一个sqlite_orm.h文件

调用的时候需要提供支持库 pthread和dl否则编译不过

	target_link_libraries ( ${CMAKE_PROJECT_NAME} PRIVATE pthread dl openxlsx)

使用笔记

适用于C++的SQLite数据库的orm,更多的用法参考git路径下的example里面的代码

以下笔记参考下面连接基本的增删查改

https://blog.csdn.net/sdut_jk17_zhangming/article/details/107610438

创建表

表结构
struct User{int id;std::string firstName;std::string lastName;int birthDate;std::unique_ptr<std::string> imageUrl;int typeId;
};struct UserType {int id;std::string name;
};
SQL语句

SQL语句

CREATE TABLE users (id integer primary key autoincrement, first_name text not null, last_name text not null, birth_date integer not null, image_url text, type_id integer not null)CREATE TABLE user_types (id integer primary key autoincrement, name text not null DEFAULT 'name_placeholder')
sqlite_orm语句

sqlite_orm语句

using namespace sqlite_orm;
auto storage = make_storage("db.sqlite",make_table("users",make_column("id", &User::id, autoincrement(), primary_key()),make_column("first_name", &User::firstName),make_column("last_name", &User::lastName),make_column("birth_date", &User::birthDate),make_column("image_url", &User::imageUrl),make_column("type_id", &User::typeId)),make_table("user_types",make_column("id", &UserType::id, autoincrement(), primary_key()),make_column("name", &UserType::name, default_value("name_placeholder"))));

在创建表时不需要指明表的列的变量类型,在创建时会通过传入的参数指针进行确定
对于私有数据类型,可以通过创建setter和getter进行赋值和访问
创建表时要指明存储的文件名,如“db.sqlite" 和表名 如 “users”,“user_types”,若要存储在内存里,文件名为":memory:"或者为空
可为列添加的属性,如自增autoincrement(),主键 primary_key(),初始值default_value(“0”)

CRUD

插入 insert
User user{-1, "Jonh", "Doe", 664416000, std::make_unique<std::string>("url_to_heaven"), 3 };
auto insertedId = storage.insert(user);

返回用户id或者抛出异常
如果要指明id,用replace()

查找
try{auto user = storage.get<User>(insertedId);cout << "user = " << user.firstName << " " << user.lastName << endl;
}catch(std::system_error e) {cout << e.what() << endl;
}catch(...){cout << "unknown exeption" << endl;
}```或者if(auto user = storage.get_pointer<User>(insertedId)){cout << "user = " << user->firstName << " " << user->lastName << endl;
}else{cout << "no user with id " << insertedId << endl;

第一种失败会抛出异常,第二种成功返回std::unique_ptr 失败返回nullptr

修改 updata

user.firstName = “Nicholas”;
user.imageUrl = “https://cdn1.iconfinder.com/data/icons/man-icon-set/100/man_icon-21-512.png”
storage.update(user);

根据id修改某一行的为主属性值

storage.update_all(set(c(&User::lastName) = "Hardey",c(&User::typeId) = 2),where(c(&User::firstName) == "Tom"));

修改符合条件的行

删除 remove

根据id修改某一行的为主属性值
storage.update_all(set(c(&User::lastName) = “Hardey”,
c(&User::typeId) = 2),
where(c(&User::firstName) == “Tom”));

修改符合条件的行
删除 remove

storage.remove<User>(insertedId)

参数是id,而不是整个对象

遍历所有对象 get.all()
auto allUsers = storage.get_all<User>();
cout << "allUsers (" << allUsers.size() << "):" << endl;
for(auto &user : allUsers) {cout << storage.dump(user) << endl; 
}

默认返回一个vector容器,可以指明返回list auto allUsersList = storage.get_all<User, std::list>();
get.all() 内存开销较大,可以逐行遍历

for(auto &user : storage.iterate<User>()) {cout << storage.dump(user) << endl;
}
复杂查询
//  SELECT doctor_id
//  FROM visits
//  WHERE LENGTH(patient_name) > 8
auto selectStatement = storage.prepare(select(&Visit::doctor_id, where(length(&Visit::patient_name) > 8)));
cout << "selectStatement = " << selectStatement.sql() << endl;  //  prints "SELECT doctor_id FROM ..."
auto rows = storage.execute(selectStatement); //  rows is std::vector<decltype(Visit::doctor_id)>//  SELECT doctor_id
//  FROM visits
//  WHERE LENGTH(patient_name) > 11
get<0>(selectStatement) = 11;
auto rows2 = storage.execute(selectStatement);
聚合函数
avg() 平均值 .avg()
count() 统计值 .count()
MAX() 最大值 .max() return std::unique_ptr
MIN() 最小值 min() return std::unique_ptr
SUM() 求和 return std::unique_ptr
TOTAL()
条件查询
auto id5and7 = storage.get_all<User>(where(c(&User::id) <= 7 and c(&User::id) >= 5 and not (c(&User::id) == 6)));
cout << "id5and7 count = " << id5and7.size() << endl;
for(auto &user : id5and7) {cout << storage.dump(user) << endl;
}

可以使用=, !=, >, >=, <, <=, IN, BETWEEN ,LIKE,AND,OR
查询某列成员

//  SELECT id FROM users WHERE last_name = 'Doe'
auto doeIds = storage.select(&User::id, where(c(&User::lastName) == "Doe"));
cout << "doeIds count = " << doeIds.size() << endl; //  doeIds is std::vector<int>
for(auto &doeId : doeIds) {cout << doeId << " ";
}
cout << endl;
查询若干列

查询若干列

//  `SELECT first_name, last_name FROM users WHERE id > 250 ORDER BY id`
auto partialSelect = storage.select(columns(&User::firstName, &User::lastName),where(c(&User::id) > 250),order_by(&User::id));
cout << "partialSelect count = " << partialSelect.size() << endl;
for(auto &t : partialSelect) {auto &firstName = std::get<0>(t);auto &lastName = std::get<1>(t);cout << firstName << " " << lastName << endl;
}
ORDER BY
//  `SELECT * FROM users WHERE id < 250 ORDER BY first_name`
auto orderedUsers2 = storage.get_all<User>(where(c(&User::id) < 250), order_by(&User::firstName));
cout << "orderedUsers2 count = " << orderedUsers2.size() << endl;
for(auto &user : orderedUsers2) {cout << storage.dump(user) << endl;
}

Transactions (事物)

其保护作用
use transaction function which begins transaction implicitly and takes a lambda argument which returns true for commit and false for rollback. All storage calls performed in lambda can be commited or rollbacked by returning true or false.
最后一句话有说lambda表达式返回true就会自动提交
林哥测试过,提交与回滚都是自动生效的
新的疑问,那么在lambda表达式中,如果数据库操作出现报错,那么软件是否会闪退呢?

当前表格中没有指定ID2 。没有Transactions 保护直接运行,软件闪退。

在这里插入图片描述

    storage.sync_schema(); //这句话会在数据库中创建表格,如果没有sqlite文件则创建该文件auto secondUser = storage.get<Table_DEV_CMD_NAME_POLL>(2);secondUser.CMD_NAME = "RRRR1";storage.update(secondUser);terminate called after throwing an instance of 'std::system_error'what():  Not found
./build_project.sh:行 63: 65589 已放弃               (核心已转储) ./Build/bin/antctrlproto

添加Transactions 效果如下,一样会闪退。

    auto commited = storage.transaction([&]() mutable{auto secondUser = storage.get<Table_DEV_CMD_NAME_POLL>(2);secondUser.CMD_NAME = "RRRR1";storage.update(secondUser);auto gottaRollback = bool(rand() % 2);if (gottaRollback){                 //  dummy condition for testreturn false; //  exits lambda and calls ROLLBACK}//  exits lambda and calls COMMITreturn true; });terminate called after throwing an instance of 'std::system_error'what():  Not found

添加try catch 可以解决软件闪退

    auto commited = storage.transaction([&]() mutable{try{auto secondUser = storage.get<Table_DEV_CMD_NAME_POLL>(2);secondUser.CMD_NAME = "RRRR1";storage.update(secondUser);}catch (const std::system_error &e){LOG(ERROR) << "get FAILE :" << e.what();}auto gottaRollback = bool(rand() % 2);if (gottaRollback){                 //  dummy condition for testreturn false; //  exits lambda and calls ROLLBACK}//  exits lambda and calls COMMITreturn true; });press anykey to running antctrlproto!2022-03-21 16:47:45,277:[ERROR] get FAILE :Not found
Commit failed, process an error
root@lkt-VirtualBox:~/gitlab/xdevice-platform-newbranch_test/xdevice-platform/test/OpenXlsx# 

性能测试

测试工程路径,放到xdevice工程下了

xdevice-platform/test/sqlite_orm_test

insert 插入

1.插入1000条数据,耗时6S

  TJ_GSCJ_DEVINFO.ID = 3;TJ_GSCJ_DEVINFO.DEV_NAME = "TJ_GSCJ";TJ_GSCJ_DEVINFO.DEV_CMD_TABLE_NAME = "TJ_GSCJ_CMDTABLE";TJ_GSCJ_DEVINFO.COMUNITATE_MODE = "TCP_SERVER";TJ_GSCJ_DEVINFO.TCP_IP = "127.0.0.1";TJ_GSCJ_DEVINFO.TCP_PORT = "5000";TJ_GSCJ_DEVINFO.UDP_IP_SRC = "Jameqs";TJ_GSCJ_DEVINFO.UDP_PORT_SRC = "Jameqs";TJ_GSCJ_DEVINFO.UDP_PORT_DST = "Jameqs";TJ_GSCJ_DEVINFO.UDP_IP_DST = "Jameqs";TJ_GSCJ_DEVINFO.UDPMC_IP = "Jameqs";TJ_GSCJ_DEVINFO.UDPMC_IP_RX = "Jameqs";TJ_GSCJ_DEVINFO.UDPMC_IP_TX = "Jameqs";TJ_GSCJ_DEVINFO.UDPMC_PORT_RX = "Jameqs";TJ_GSCJ_DEVINFO.UDPMC_PORT_TX = "Jameqs";printf_init_log("start  sqlite_orm_write_test");int key = 1000; //写1000条大概,耗时6while (key != 0){storage.insert(TJ_GSCJ_DEVINFO); //大概在4-8mskey--;}printf_init_log("#############################start  read sqlite_orm_write_test");

2.单条数据插入时间

  storage.replace(SQLORM_XPRO_DEVINFO{1, "James", "James", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston", "Houston"}); //大概在6-8msstorage.insert(TJ_GSCJ_DEVINFO);  //大概在4-8ms

读取

1.读取耗时

同一时间只有一个线程在做读取

        //  读取次数     耗时//  90000        57-58ms// 一次读6000    4-5ms// 1000          2m// 500           1m
printf_init_log("#############################start  read sqlite_orm_write_test");
auto simpleRows = storage.select(columns(&SQLORM_XPRO_DEVINFO::ID, &SQLORM_XPRO_DEVINFO::DEV_NAME, &SQLORM_XPRO_DEVINFO::DEV_CMD_TABLE_NAME)); //几乎不耗时 小于1ms
printf_init_log("#############################end read  sqlite_orm_write_test");
2.一对一的读取

循环读取,不带延时。读取正常,没有闪退

void *thread_GSCJQ1(void *arg)
{while (1){LOG(INFO) << "#############################start  read sqlite_orm_write_test";try{auto simpleRows = storage1.select(columns(&SQLORM_XPRO_DEVINFO::ID, &SQLORM_XPRO_DEVINFO::DEV_NAME, &SQLORM_XPRO_DEVINFO::DEV_CMD_TABLE_NAME)); //几乎不耗时 小于1ms}catch (const std::system_error &e){cout << "11111111111" << e.what() << endl;}}
}
3.多对一的读取

起两个线程,循环读取,不带延时。读取正常,没有闪退

注意,两个线程的句柄需要不同。

void *thread_GSCJQ1(void *arg)
{while (1){LOG(INFO) << "#############################start  read sqlite_orm_write_test";try{auto simpleRows = storage1.select(columns(&SQLORM_XPRO_DEVINFO::ID, &SQLORM_XPRO_DEVINFO::DEV_NAME, &SQLORM_XPRO_DEVINFO::DEV_CMD_TABLE_NAME)); //几乎不耗时 小于1ms}catch (const std::system_error &e){cout << "11111111111" << e.what() << endl;}}
}void *thread_GSCJQ2(void *arg)
{while (1){LOG(TRACE) << "__________________start  read sqlite_orm_write_test";try{auto simpleRows = storage2.select(columns(&SQLORM_XPRO_DEVINFO::ID, &SQLORM_XPRO_DEVINFO::DEV_NAME, &SQLORM_XPRO_DEVINFO::DEV_CMD_TABLE_NAME)); //几乎不耗时 小于1ms}catch (const std::system_error &e){cout << "22222222" << e.what() << endl;}}
}

Q&A

Q1:如果同一个结构体生成了多份表格,如何指定表格名字进行查询

sqlite_orm看example中都是通过结构体名来对数据库进行增删查改。表格名字这个参数只在创建表格的时候用一下。
目前没有找到通过结构体名+表格名的方式进行指定查询的情况。
也没有看到明确的说法说不行。把example下面的例子都看了,没有我想要的方法。
sqlite_orm  结构体名和数据库的表格是1:1对应的。

Q2: wiki上说了,在事务结束的时候让我们调用提交commit() 或者回滚,但是林哥的代码里面没有调用提交。

在这里插入图片描述

use transaction function which begins transaction implicitly and takes a lambda argument which returns true for commit and false for rollback. All storage calls performed in lambda can be commited or rollbacked by returning true or false.
最后一句话有说lambda表达式返回true就会提交
林哥测试过,提交与回滚都是自动生效的
新的疑问,那么在lambda表达式中,如果数据库操作出现报错,那么软件是否会闪退呢?

## 附录1.vscode 查看sqlite表格,还不错

https://blog.csdn.net/weixin_43739167/article/details/113843871

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/578285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Spring实战】05 CommandLineRunner

文章目录 1. 简介2. 用法1&#xff09;单个 CommandLineRunner2&#xff09;多个 CommandLineRunner 3. 优点4. 缺点总结 CommandLineRunner 是 Spring Boot 提供的一个接口&#xff0c;用于在 Spring Boot 应用程序启动后执行一些任务。通过实现 CommandLineRunner 接口&#…

JDKtomcat环境配置共享目录防火墙

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《产品经理如何画泳道图&流程图》 ⛺️ 越努力 &#xff0c;越幸运 目录 1、配置JDK 2、配置tomcat 3、配置文件夹共享功能 4、防火墙配置 5、思维导图 1、配置JDK 建立一个共…

目标检测-Two Stage-RCNN

文章目录 前言一、R-CNN的网络结构及步骤二、RCNN的创新点候选区域法特征提取-CNN网络 总结 前言 在前文&#xff1a;目标检测之序章-类别、必读论文和算法对比&#xff08;实时更新&#xff09;已经提到传统的目标检测算法的基本流程&#xff1a; 图像预处理 > 寻找候选区…

微服务架构<2>

在电商项目中&#xff0c;我们针对一些核心业务&#xff0c;比较复杂的业务需要做一些设计以及优化的过程首先我们针对于订单的模块拆分了2个子模块1.order-curr实时下单业务 2.order-his 做一些历史的订单归档我们的订单业务 >商品添加至购物车 >购物车结算--> 订单…

摇杆控制人物移动

摇杆控制人物移动 一、UI搭建二、3d模型搭建三、脚本JoyStickBar.csPlayerController.cs 工程在我资源里名字叫Joystickbar.unitypackage [连接](https://download.csdn.net/download/qq_42194657/12043019?spm1001.2014.3001.5503) 一、UI搭建 JoyStickBar是图片背景 JoySt…

算法设计与分析实验报告-分治法相关练习题

课本分治法章节课后部分练习题。 算法设计与分析实验报告-递归与分治策略 算法设计与分析实验报告-动态规划算法 算法设计与分析实验报告-回溯法 算法设计与分析实验报告-分治法相关练题 北京大学出版社-算法设计与分析 五、程序题 1. 试给出用分治法求某集合中元素值为偶…

ArkUI动画概述

目录 1、按照页面分类 2、按照功能分类 3、显示动画 4、属性动画 动画的原理是在一个时间段内&#xff0c;多次改变UI外观&#xff0c;由于人眼会产生视觉暂留&#xff0c;所以最终看到的就是一个“连续”的动画。UI的一次改变称为一个动画帧&#xff0c;对应一次屏幕刷新&a…

一开始我还不信!高德导航红绿灯竟然能读秒?

高德导航红绿灯为啥能读秒&#xff1f; 1 内部员工吐露 每天工作其实就是负责自己片区的红绿灯&#xff0c;一大早就去校对时间&#xff0c;然后发布到后台。是的&#xff0c;统计出来的&#xff0c;而且还是人工统计&#xff0c;有误差请见谅[害羞] 真的是很辛苦了&#xf…

如何使用队列处理 API 速率限制

对于遇到速率限制的应用程序来说也是一个挑战&#xff0c;因为它需要“放慢速度”或暂停。这是一个典型的场景&#xff1a; 初始请求&#xff1a;当应用程序发起与 API 的通信时&#xff0c;它会请求特定的数据或功能。API 响应&#xff1a; API 处理请求并响应请求的信息或执…

12.25

led.c #include "led.h" void all_led_init() {RCC_GPIO | (0X3<<4);//时钟使能GPIOE_MODER &(~(0X3<<20));//设置PE10输出GPIOE_MODER | (0X1<<20);//设置PE10为推挽输出GPIOE_OTYPER &(~(0x1<<10));//PE10为低速输出GPIOE_OSPEED…

单集群400TB,OceanBase稳定支撑快手核心业务场景

一款日均超过千万人访问的短视频 App 快手&#xff0c;面对高并发流量如何及时有效地处理用户请求&#xff1f;通过在后端配置多套 MySQL 集群来支撑高流量访问&#xff0c;以解决大数据量存储和性能问题&#xff0c;这种传统的 MySQL 分库分表方案有何问题&#xff1f;快手对分…

评估回馈电子负载的重要指标?

回馈电子负载是用于测试电源、电池和其他电子设备性能的设备。它可以模拟实际负载&#xff0c;同时将多余的能量回馈到电网或电池中。在选择和使用回馈电子负载时&#xff0c;有几个重要的指标需要考虑&#xff1a; 功率范围&#xff1a;回馈电子负载的功率范围是指其能够提供的…

巅峰画师Midjourney:新时代的独角兽

介绍 AI绘画领域中&#xff0c;Midjourney处于绝对地位&#xff0c;并且一年时间就登顶。 Midjourney是一家独立的AI研究实验室,探索新的思维媒介,拓展人类的想象力。 它由一个小型的自筹资金团队组成,专注于设计、人类基础设施和AI。 在AI绘画领域,Midjourney取得了非常突出…

百度Apollo五步入门自动驾驶:Dreamview与离线数据包分析(文末赠送apollo周边)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 粉丝福利活动 ✅参与方式&#xff1a;通过连接报名观看课程&#xff0c;即可免费获取精美周边 ⛳️活动链接&#xf…

【PDF密码】 一键强制去掉pdf密码

想要给PDF文件设置一个密码防止他人对文件进行编辑&#xff0c;那么我们可以对PDF文件设置限制编辑&#xff0c;设置方法很简单&#xff0c;我们在PDF编辑器中点击文件 – 属性 – 安全&#xff0c;在权限下拉框中选中【密码保护】 然后在密码保护界面中&#xff0c;我们勾选【…

通过three.js玩转车展项目

1.项目搭建 1.1 创建文件夹 mkdir 文件名1.2 初始化package.json npm init -y1.3 安装打包工具并配置相关依赖 npm i parcel -d在package.json中打包路径和指令 1.4 安装three.js npm i three -d2.项目搭建 2.1 新建index.html&#xff0c;并再index.html引入car.js,在…

从流星雨启程:Python和Pygame下载与安装全过程

文章目录 一、前言二、下载安装过程1.官网下载安装包2.安装python过程第一步第二步第三步第四步第五步安装完成 3.简单测试Python3.1 检查 Python 版本号3.2 打开 Python 解释器3.3 输入你的第一个代码3.4 运行 Python 脚本 4.安装Pygame4.1 cmd命令安装Pygame4.2 pip升级4.3 安…

实战:朴素贝叶斯文本分类器搭建与性能评估

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Java 快速入门

简介 跨平台性&#xff1a;Java 最大的优势之一就是跨平台性&#xff0c;即一份 Java 程序可以在多平台上运行&#xff0c;而无需重写。 简单易学&#xff1a;Java 的语法和面向对象的开发方式非常简单易学。 安全性&#xff1a;Java 对于安全性的处理非常慎重&#xff0c;对…

接口测试和功能测试

本文主要分为两个部分&#xff1a; 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者之前的区别与联系。但该部分只交代了怎么做和如何做&#xff1f;并没有解释为什么要做&#xff1f; 第二部分&#xf…