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 接口&#…

HarmonyOS共享包应用内HSP开发指导

应用内HSP开发指导 应用内HSP指的是专门为某一应用开发的HSP&#xff0c;只能被该应用内部其他HAP/HSP使用&#xff0c;用于应用内部代码、资源的共享。 应用内HSP跟随其宿主应用的APP包一起发布&#xff0c;与该宿主应用具有相同的包名和生命周期。 开发应用内HSP HSP模块…

【Qt-Button】

Qt编程指南 ■ QPushButton去除虚线边框&#xff1a;QPushButton 中添加 buttonGroup组合互斥按钮QPushButton *bt static_cast<QPushButton *>(sender()) ■ QToolButton■ QRadioButton■ QCommandLinkButton■ QDialogButtonBox■ QButtonGroup■■■■ ■ QPushButt…

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

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

【数字IC设计】Verilog计算x/255的商和余数

问题描述 已知x是16位无符号整数,求x除以255的余数和商。尽量降低实现方式的硬件开销(包括面积和时序) 思路 由于除数255是一个常数,因此,直观上给人的感觉就是应该有相应的优化方法,即相对于除数可变的实现方式,在面积、时序方面应该有所改善。 对于该问题,本文给出…

目标检测-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…

培训班毕业生的出路

前面几篇文章讲的都是如何规避培训班的包装简历&#xff0c;是不是意味着包装简历就没有机会了呢&#xff1f; 首先一点&#xff0c;以我了解的帝都IT市场&#xff0c;各种各样的IT公司数目繁多&#xff0c;面试官的水平也是参差不齐&#xff0c;更何况还有onsite&#xff08;…

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

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

Nestjs使用log4j打印日志

众所周知&#xff0c;nest是自带日志的。但是好像没有log4j香&#xff0c;所以咱们来用log4j吧~ 我只演示最简单的用法&#xff0c;用具体怎么样用大家可以自己进行封装。就像前端封装自己的请求一样。 一、安装 yarn add log4js stacktrace-js 二、使用 主要就三个文件&a…

ArkUI动画概述

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

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

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

npm常见错误

三个方面 1. npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! phantomjs-prebuilt2.1.15 install: node install.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the phantomjs-prebuilt2.1.15 install script. np…

如何使用队列处理 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…