SQLiteC/C++接口详细介绍之sqlite3类(五)

2024-03-14 06:36

本文主要是介绍SQLiteC/C++接口详细介绍之sqlite3类(五),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   快速跳转文章列表:SQLite—系列文章目录

上一篇:SQLiteC/C++接口详细介绍之sqlite3类(四)

 下一篇:SQLiteC/C++接口详细介绍之sqlite3类(六)(未发表)

14.sqlite3_busy_handler函数:

用于在访问共享数据库时处理数据库锁定,并如果某个共享数据库已经处于锁定状态,则可以排队查询等待一段时间,或在达到最大等待时限时放弃等待查询,从而避免资源浪费和死锁问题。

函数的原型:

int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);

其中第一个参数是要操作的数据库句柄,第二个参数是一个函数指针,用于在数据库被锁时进行回调,第三个参数是传递给回调函数的上下文参数。
回调函数需要返回一个值,以确定是否继续等待或放弃查询等待,如果返回0,则一直等待,如果返回非零值,则直接中断查询。
注意:sqlite3_busy_handler函数不能在事务过程中使用,否则会影响数据库会话的一致性和完整性。因此,在使用此函数之前,应先检查当前是否存在任何激活的事务,并在必要时回滚事务,以免引起意外的数据库文件损坏。

例如:

1. 定义回调函数:为了使用sqlite3_busy_handler(),需要先定义一个回调函数。该函数有两个参数,即被占用的数据库对象和被占用次数。如果该函数返回0,则表示可以继续尝试访问该对象;如果返回非0值,则表示等待指定时间后再次尝试访问。

   static int callback(void *data, int count) {int delay = 1000;printf("Database is busy, waiting %d ms...\n", delay);usleep(delay * 1000);return 1;}

   在上面的代码中,我们定义了一个名为callback()的回调函数,当访问数据库时发生"Busy"错误时,该函数将等待1秒后再次尝试访问。如果该回调函数返回1,则下次访问将再次询问该回调函数。
2. 注册回调函数:在使用sqlite3_open()打开数据库时,可以使用sqlite3_busy_handler()函数注册上面定义的回调函数。

   sqlite3 *db;int rc = sqlite3_open("mydb.db", &db);if (rc == SQLITE_OK) {sqlite3_busy_handler(db, callback, NULL);// ...}   

   在上面的代码中,我们在打开名为mydb.db的数据库时,使用了sqlite3_busy_handler()函数注册了callback()回调函数。
在使用sqlite3_busy_handler()处理"Busy"错误时,需要注意一些问题:
- 该函数注册的回调函数只有在执行一些特定的SQL语句时才会被调用,例如UPDATE、INSERT、DELETE等更新操作。
- 回调函数需要注意自旋锁问题(spin-lock),以防止死循环和线程或进程卡死。
- 注册回调函数可能会影响数据库的性能,因此需要根据具体情况进行测试和调整。
在多个线程或者进程并发访问SQLite数据库时,使用sqlite3_busy_handler()函数可以有效地避免"Busy"错误,并提高程序的可靠性和稳定性。

15.sqlite3_db_name函数

在多数据库连接的情况下用于获取给定数据库连接或游标所关联的数据库的名称。这个函数可以用于跟踪数据库文件的来源及管理,特别是在使用动态绑定的SQL语句时。 

函数的原型:

const char *sqlite3_db_name(sqlite3 *db, const char *zDbName);
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);

其中db参数是一个指向SQLite数据库连接对象的指针,zDbName参数是一个指向包含所需数据库名称的字符数组的指针。如果第二个参数不为NULL,则该函数将获取指定列,否则默认获取主数据库连接或游标所关联的数据库名称。
函数返回值是一个指向包含数据库名称的空终止字符串的指针。如果指定的数据库不存在,则返回NULL。
注意:sqlite3_db_name函数只能在一个已打开的数据库连接上使用,并且仅能返回当前打开的数据库的名称,不能获取SQLite中所有数据库的名称。如果需要获取所有数据库的名称,则需要执行SQLite系统表查询或系统函数调用。 

例如:

下面是sqlite3_db_name()的使用方法:
 获取数据库名称:使用sqlite3_db_name()函数获取该连接对象关联的数据库名称。  

 const char *db_name = sqlite3_db_name(db, 0);printf("Database name: %s\n", db_name);

  在上面的代码中,我们使用sqlite3_db_name()函数获取与db连接相关联的数据库的名称,并将其打印出来。
注意:如果一个数据库连接关联多个数据库,比如通过ATTACH命令关联多个数据库时,sqlite3_db_name()函数将返回最近一次执行的SQL语句中指定的数据库名称。如果没有指定数据库名称,则返回NULL。 

16.sqlite3_busy_timeout函数

设置在多用户或多线程并发访问文件时等待其它连接锁释放的最大时间。当某个连接在对资源进行访问时,如果资源已被另一个连接锁定,则该连接将等待指定的时间,直到资源被释放或达到指定的最大等待时间为止。

函数的原型:

int sqlite3_busy_timeout(sqlite3*, int ms);

 其中ms参数表示等待的毫秒数,如果为非正数,则取消忙等待并释放连接锁。函数的返回值表示是否设置成功,如果返回SQLITE_OK,则表示设置成功,否则返回相应的错误码。
注意:sqlite3_busy_timeout函数必须在连接之前进行调用,否则设置将不起作用。此外,在使用此函数时应注意避免死锁问题,例如设置一个合适的等待时间,并在必要时使用函数进行回调,以避免长时间等待导致资源浪费和死锁问题。

1. 设置"busy"超时:使用sqlite3_busy_timeout()函数设置在访问数据库时发生"Busy"错误时等待的时间,单位为毫秒。
 

  sqlite3_busy_timeout(db, 5000);

  在上面的代码中,我们设置等待时间为5000毫秒,即5秒。
2. 访问数据库:在设置"busy"超时后,可以开始访问数据库。

   int result = sqlite3_exec(db, "SELECT * FROM mytable", callback, 0, &zErrMsg);if (result != SQLITE_OK) {fprintf(stderr, "SQL error: %s\n", zErrMsg);sqlite3_free(zErrMsg);}

在上面的代码中,db是我们打开数据的对象我们使用sqlite3_exec()函数执行SQL语句并处理结果。
注意:
sqlite3_busy_timeout()只对在访问数据库时发生的"Busy"错误起作用。如果程序占用数据库长时间不释放,造成阻塞,这时sqlite3_busy_timeout()就不起作用了。在实际使用中,应该在编写程序时避免出现长时间占用数据库的情况。

17.sqlite3_db_readonly函数用于判断指定的数据库连接或游标是否处于只读模式。 

函数的原型:

int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);

其中,参数db是一个指向SQLite数据库连接对象的指针,参数zDbName是一个指向包含所需数据库名称的字符数组的指针。如果第二个参数不为NULL,则该函数将获取指定列,否则默认获取主数据库连接或游标所关联的数据库。
函数返回值是一个整数,表示指定数据库是否处于只读模式。返回值为1时表示该数据库处于只读模式,返回值为0表示该数据库可以进行读写操作。
注意:此函数只能用于已经打开的数据库连接或游标。  

例如: 

判断数据库是否为只读:使用sqlite3_db_readonly()函数判断数据库是否为只读。

int is_readonly = sqlite3_db_readonly(db, "main");
if (is_readonly == 1) {printf("The database is readonly\n");} else {printf("The database is not readonly\n");}

代码中,db是数据库连接对象,使用sqlite3_db_readonly()函数判断与db对象相关联的名为main的数据库是否为只读。如果该数据库只读,则打印"The database is readonly",否则打印"The database is not readonly"。
注意:sqlite3_db_readonly()函数的第二个参数指定要查询的数据库名称。如果没有指定任何数据库名称,则默认查询"main"数据库。如果指定的数据库不存在,则返回-1。 

18.sqlite3_last_insert_rowid

函数用于获取最近插入数据的行ID 。

函数的原型:

sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);

函数返回一个sqlite_int64类型的值,表示最近一次插入数据的行ID。如果还未插入数据,则返回0。

例如:

在SQLite中,当表定义了一个自增长的主键字段时,插入一条新记录时,该字段将自动生成一个独一无二的值,我们可以使用sqlite3_last_insert_rowid()函数获取该值。
下面是sqlite3_last_insert_rowid()的使用方法:
1. 执行插入操作:使用SQL语句执行一条INSERT操作,在执行插入操作时,必须包含自增长的主键列。  

 sqlite3 *db;int rc = sqlite3_open("mydb.db", &db);if (rc == SQLITE_OK) {char *sql = "INSERT INTO mytable (name, age) VALUES ('Tom', 25)";rc = sqlite3_exec(db, sql, NULL, NULL, NULL);if (rc != SQLITE_OK) {printf("Error: %s\n", sqlite3_errmsg(db));}      }  

在上面的代码中,我们使用sqlite3_exec()函数执行一条INSERT语句,插入一条记录到名为mytable的表中。
2. 获取主键值:使用sqlite3_last_insert_rowid()函数获取自动生成的主键值。  

sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(db);
printf("Last insert rowid: %lld\n", last_rowid);

  代码中,我们使用sqlite3_last_insert_rowid()函数获取刚插入记录的主键值,并将其打印出来。

注意:该函数只能用于最近执行的INSERT或REPLACE命令之后,否则将返回不可预测的结果。该函数不需要连接句柄或游标对象进行调用,只需要在执行INSERT或REPLACE命令之后立即调用即可。sqlite3_last_insert_rowid()函数获取自动生成的主键值只针对自增长的主键列有效,并且只能获取最近插入的记录的主键值。如果不存在自增长的主键列或者没有执行任何插入操作,则该函数返回0。

这篇关于SQLiteC/C++接口详细介绍之sqlite3类(五)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807523

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}