嵌入式下C/C++调用sqlite3简单开发

交叉编译sqlite3请关注我第一篇博文

sqlite3 交叉编译-CSDN博客

sqlite3的命令的简单使用(增删改查,创建/删除表)请关注我的上一篇博文

sqlite3嵌入式使用以及C/C++代码开发-CSDN博客

一、新建文件夹

此文件夹用于放置工程,比如我的文件夹叫sqliteDemo,将交叉编译编译好的sqlite3的lib文件夹和头文件放置在工程目录下

sqliteDemo文件夹下文件如下

二、创建测试文件

创建一个c文件,比如我的为main.c

在C文件中写入如下内容

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

int main(void)
{
    sqlite3 *ppdb;
    int ret = sqlite3_open("student.db",&ppdb);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_open Failed -- %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    return 0;
}

三、编译测试

执行命令 arm-linux-gnueabihf-gcc main.c -o sql -L./lib -lsqlite3

则生成一个命令 sql 的可执行文件

四、运行

将sql拷贝到开发板中的某个位置,执行 ./sql 即可运行

五、sqlite函数说明

sqlite3库函数在其官网有对应的说明,可登录其网站查阅

SQLite Home Page

其中,introduction列出了常用的几个函数,如果想看更多函数,可查看其函数列表网页List Of SQLite Functions

对于一般想小型开发,仅需掌握如下四个函数即可:

sqlite3_open()

sqlite3_close()

sqlite3_exec()

sqlite3_get_table()

下面对最常用几个函数进行介绍

sqlite3_open()

此函数功能为创建数据库,如果数据库已经创建,则打开数据库,函数原型如下Opening A New Database Connection

filename为数据库的名字,即执行 ./sqlite3 student命令时的student这个值

ppDb为数据库句柄,后续对数据库的所有操作都通过此句柄进行传值。

使用举例:

cpp 复制代码
​
sqlite3 *ppDb;

int ret = sqlite3_open("student.db", &ppDb);

if(ret != SQLITE_OK)
{ 
    printf("Open Sqlite3 Failed : %s\n",sqlite3_errmsg(ppDb));
}

​
复制代码
https://www.sqlite.org/c3ref/close.html 

此函数功能为关闭数据库,如果sqlite3对象被成功销毁并且所有相关资源都被释放,则对sqlite3_close()的调用返回SQLITE_OK。函数原型如下Closing A Database Connection

使用举例
cpp 复制代码
sqlite3 *ppDb;

int ret = sqlite3_open("student.db", &ppDb);

if(ret != SQLITE_OK)
{ 
    printf("Open Sqlite3 Failed : %s\n",sqlite3_errmsg(ppDb));
}

ret = sqlite3_close(ppDb);    //关闭数据库

if(ret != SQLITE_OK)
{ 
    printf("Release Sqlite3 Failed : %s\n",sqlite3_errmsg(ppDb));
}

sqlite3_exec()

此函数为sqlite3函数的重中之重,用它可以执行几乎所有的sqlite3命令。函数原型如下One-Step Query Execution Interface

第一个参数 sqlite3*,为一个打开的数据库的句柄,比如前面sqlite3_open函数中ppDb参数。

第二个参数为填有sql的命令行语句的字符串

第三个参数为回调函数。回调函数返回值为 int。但此参数只对有显示的命令行有效,比如:select * from student命令

第四个参数为回调函数需要传入的参数,即回调函数的第一个参数值

第五个保存错误消息

使用举例一

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

int main(void)
{
	//打开或者创建数据库文件
	sqlite3 *ppdb;
	int ret = sqlite3_open("student.db",&ppdb);
	if(ret != SQLITE_OK)
	{
		printf("Open Sqlite Failed -- %s\n",sqlite3_errmsg(ppdb));
		exit(1);
	}
	
	//创建数据表
	char *sqltCmd = "create table student (id integer, name txt, age integer);";
	ret = sqlite3_exec(ppdb, sqltCmd, NULL, NULL, NULL);
	if(ret != SQLITE_OK)
	{
		printf("sqlite3_exec1 Failed! -- %s\n", sqlite3_errmsg(ppdb));
		exit (1);
	}
	
    //再次创建数据表
	char *errmsg;
	ret = sqlite3_exec(ppdb, sqltCmd, NULL, NULL, &errmsg);	//第五个参数保存错误消息
	if(ret != SQLITE_OK)
	{
		//因为sqltCmd中的命令重复创建了数据表,所以会报错,命令行中的错误会通过errmsg指针返回
		//可以通过命令行输入两遍 sqltCmd 命令对比程序运行中的下一行打印
		printf("sqlite3_exec1 Failed! -- %s\n", sqlite3_errmsg(ppdb));
		exit (1);
	}
	
	ret = sqlite3_close(ppdb);
	if(ret != SQLITE_OK)
	{
		printf("Sqlite Release Failed -- %s\n",sqlite3_errmsg(ppdb));
		exit(1);
	}
	return 0;
}

使用举例二

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"

/*
print函数每查询一行,就执行一次,故无需返回数据库的数据条数,也为行数
sql:需要传入的其它参数
colum:返回数据库的字段数,也为列数
value: 返回字段的值
name:返回字段的名称
*/
int print(void * sql, int column, char** value, char ** name)
{
	printf("第一个参数示例:%s\n",sql);
    int i;
    for(i = 0; i < column; i++)
    {
        printf("%s=%s  ", name[i], value[i]);
    }
    printf("\n");
    return 0;
}


int main(void)
{
    //创建或打开数据库
    sqlite3 *ppdb;
    int ret = sqlite3_open("student.db", &ppdb);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_open : %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }

	//创建表 student
    char* sql = "create table if not exists student (id integer, name txt, age integer);";
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_exec1 : %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }

    char cmd[256] = {0};
    int id, age, i;
    char name[256]={0};
    for(i = 0; i < 2; i++)
    {
        printf("请输入学号、名字和年龄:\n");
        scanf("%d%s%d",&id,name,&age);
        memset(cmd, 0, sizeof(cmd));
        sprintf(cmd,"insert into student (id, name, age) values(%d, '%s', %d);",id,name,age);
        ret = sqlite3_exec(ppdb, cmd, NULL, NULL, NULL);
        if(ret != SQLITE_OK)
        {
            printf("sqlite3_exec2 : %s\n", sqlite3_errmsg(ppdb));
            exit(1);
        }
    }
	
	memset(cmd, 0, sizeof(cmd));
	sprintf(cmd,"select * from student;");
	ret = sqlite3_exec(ppdb, cmd, print, sql, NULL);//此处sql仅仅是用来说明传参问题
	if(ret != SQLITE_OK)
	{
		printf("sqlite3_exec3 : %s\n", sqlite3_errmsg(ppdb));
		exit(1);
	}
	
	ret = sqlite3_close(ppdb);
	if(ret != SQLITE_OK)
	{
		printf("sqlite3_close : %s\n", sqlite3_errmsg(ppdb));
		exit(1);
	}
    return 0;
}
    

执行效果如下

sqlite3_exec函数回调参数的再说明

以 使用举例二 为例,假如此时数据表中含有4项数据

在调用sqlite3_exec函数查询数据表时

每查询到一条数据,则调用一次 回调函数 print。

假如现在查询完第一条数据,即 1|aa|11

则返回列数为 3(形参column 为 3),数据值为 1 aa 11 的字符串(即 *value 指向{"1", "aa", "11"}的字符串首地址),字段值为 id name age 的字符串(即*name 指向{"id","name","age"}的字符串的首地址)

因此,可以通过 value[i] 和 name[i] 找到对应的字符串

此函数为sqlite3专门用于查询语句的函数,函数原型如下

Convenience Routines For Running Queries

第一个参数为数据库的句柄

第二个参数为填有sql的命令行语句的字符串

第三个参数为查询后的返回值

第四个参数为查询到数据库中数据的条数(即行数)

第五个参数为查询到数据库中数据的字段数(即列数)

第三参数pazResult为一个一维数组,存放方式为 表头,表1对应的值,表2对应的值......

仍然以前面数据库为例说明

pazResult中数据存放方式如下图所述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"

int main(void)
{
    //创建或打开数据库
    sqlite3* ppdb;
    int ret = sqlite3_open("student.db",&ppdb);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_open : %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }

    char* sql = "create table student(id integer, name text, age integer);";
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_exec1 : %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }

    char cmd[256] = {0};
    int id, age, i, j;
    char name[128] = {0};
    for(i = 0; i < 2; i++)
    {
        printf("请输入学号、名字和年龄:\n");
        scanf("%d%s%d",&id, name, &age);
        memset(cmd, 0, sizeof(cmd));
        sprintf(cmd, "insert into student(id, name, age) values (%d, '%s', %d);",id,name,age);
        ret = sqlite3_exec(ppdb, cmd, NULL, NULL, NULL);
        if(ret != SQLITE_OK)
        {
            printf("sqlite3_exec2 : %s\n", sqlite3_errmsg(ppdb));
            exit(1);
        }
    }
    
    char **result;
    int row, column;
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "select * from student;");
    ret = sqlite3_get_table(ppdb, cmd, &result, &row, &column, NULL);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_get_table: %s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
	
	int Index = column;
    for(i = 0; i < row; i++)
    {
        for(j = 0; j < column; j++)
        {
            //result[j]是指的表头的三个字符串
            //result[Index]是指的实际数据,实际数据是跨过表头后从column开始的数据
            //参照上面的内存截图理解
            printf("%s=%s  ",result[j], result[Index]);
			Index++;
        }
        printf("\n");
    }

    return 0;
}

实际执行效果如图

相关推荐
高兴就好(石2 小时前
DB-GPT部署和试用
数据库·gpt
这孩子叫逆2 小时前
6. 什么是MySQL的事务?如何在Java中使用Connection接口管理事务?
数据库·mysql
Karoku0662 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构
码农郁郁久居人下3 小时前
Redis的配置与优化
数据库·redis·缓存
MuseLss4 小时前
Mycat搭建分库分表
数据库·mycat
Hsu_kk4 小时前
Redis 主从复制配置教程
数据库·redis·缓存
DieSnowK4 小时前
[Redis][环境配置]详细讲解
数据库·redis·分布式·缓存·环境配置·新手向·详细讲解
程序猿小D4 小时前
第二百三十五节 JPA教程 - JPA Lob列示例
java·数据库·windows·oracle·jdk·jpa
Flerken1015 小时前
数据库语言、SQL语言、数据库系统提供的两种语言
数据库·sql·oracle
掘根5 小时前
【网络】高级IO——poll版本TCP服务器
网络·数据库·sql·网络协议·tcp/ip·mysql·网络安全