一.sqlite库函数
1.sqlite3_open()函数
语法:*sqlite3_open(const char *filename, sqlite3 *ppDb)
作用:该例程打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据库连接对象。
参数1:如果 filename 参数是 NULL或":memory:",那么 sqlite3_open() 将会在 RAM 中创建一个内存数据库,这只会在 session 的有效时间内持续。如果文件名 filename 不为 NULL,而是你创建的数据库文件名,那么 sqlite3_open() 将使用这个参数值尝试打开对应数据库文件。如果该名称的文件不存在,sqlite3_open() 将创建一个新的命名为该名称的数据库文件并打开。
参数2:sqlite3_open()
函数的第二个参数是一个指向 SQLite 数据库连接的指针。如果 sqlite3_open()
调用成功,该指针将指向新创建的数据库连接,您可以使用该指针执行其他 SQLite 操作,如执行 SQL 查询、管理数据库事务等。
返回值:sqlite3_open()
函数的返回值是一个整数,用于指示函数调用的结果。以下是可能的返回值:
SQLITE_OK
:函数调用成功,已打开指定的数据库连接。SQLITE_ERROR
:发生了错误,无法打开数据库连接。例如,文件名无效或无法访问文件系统。SQLITE_CANTOPEN
:无法打开数据库文件。这可能是因为磁盘已满、权限不足或数据库文件损坏等原因导致的。SQLITE_MISUSE
:发生了程序错误,例如传递给函数的参数无效或在多线程环境中不正确地使用库函数。- 其他错误码:SQLite 库定义了许多其他可能的错误代码,每个代码表示一个特定类型的错误。
通常来说,如果您调用 sqlite3_open()
并且它返回 SQLITE_OK
,这个你作为0理解,其他错误代表返回值为1,只是不同类型的1代表的错误不同而已,则可以开始使用通过该函数创建的数据库连接进行其他 SQLite 操作,否则需要检查返回值并根据具体情况采取必要的措施。
2. sqlite3_errmsg()函数
语法:const char *sqlite3_errmsg(sqlite3*);
参数:参数是一个 sqlite3
类型的指针,该指针代表与 SQLite 数据库关联的连接。
返回值:它返回一个指向包含最近一次执行 SQLite API 函数时发生的错误消息的静态字符串的指针。
3. sqlite3_close()函数
语法:sqlite3_close(sqlite3*)
作用:关闭之前调用 sqlite3_open() 打开的数据库连接
参数:一个 sqlite3
类型的指针
4. sqlite3_exec()函数
sqlite3_exec函数是SQLite库中的一个高级封装函数,用于执行SQL语句并返回执行结果。
函数原型:
int sqlite3_exec(
sqlite3*, // 数据库连接对象
const char *sql, // 要执行的SQL语句
int (*callback)(void*,int,char**,char**), // 回调函数指针
void *, // 回调函数参数
char **errmsg // 错误信息输出缓冲区
);
参数说明:
sqlite3*
:已经打开的数据库连接对象;const char *sql
:要执行的SQL语句,可以是一条或多条SQL语句,语句之间用分号隔开;int (*callback)(void*,int,char**,char**)
:回调函数指针,当SQL语句执行完毕后会调用该函数,该函数可以用于处理查询结果或者操作完成的回调;void*
:回调函数所需的参数;char **errmsg
:如果执行过程中发生错误,将会把错误信息存到该变量所指向的内存空间中。(注意,这里是一个二级指针)
函数返回值为整数类型,表示执行结果。如果执行成功,则返回 SQLITE_OK(0); 如果执行失败,则返回其他的错误码,例如 SQLITE_ERROR(-1) 等。
注意事项:
- 在使用sqlite3_exec函数时,需要特别注意SQL注入问题,应该避免直接在SQL语句中拼接用户输入的字符串,而应该采用参数绑定的方式。
- 在使用回调函数时,需要根据具体情况做好内存管理,避免内存泄漏等问题。
5.连接测试代码
#include <stdio.h>
#include <sqlite3.h>
int main()
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
sqlite3_close(db);
}
此代码仅完成测试功能,没有实现其他功能。
二.链接数据库
1.下载sqlite3.h文件
下载链接在我上一篇博客里面有,可以查看上一篇博客sqlite基础
下载后记得解压到和你准备链接的数据库.db文件同一目录下。
2.链接
如果此时你运行测试文件,结果绝对报错,因为大多数windows下的编译软件带的库中都没有sqlite3.h库文件,此时你需要进行链接操作生成可执行文件。
具体怎么链接,每个编译软件不同,这里以CLion为例,进行演示。如果你的软件是DevC++,链接操作可以参考这篇博客Windows下链接。
操作步骤:
- 1.下载好的sqlite3.h文件放在你准备链接的数据库文件同一目录下
- 2.打开CLion,新建项目,工作目录选择你刚刚存放的位置
- 3.编写CMake文件,代码在下面,复制粘贴即可,自动保存
- 4.在main.c文件里写测试代码,编译运行
CMake代码:
cmake_minimum_required(VERSION 3.25)
project(db_work C)
set(CMAKE_C_STANDARD 11)
add_compile_options(-l sqlite3)
add_executable(db_work main.c sqlite3.c)
现在看不懂也没关系,后面会有一篇博客专门介绍makefile的,到时详细解释。
三.C语言实现sqlite操作
1.提前看
首先我们通过命令窗口,直到数据库文件原来就存在的信息,确保后面增加的信息是通过C语言操作实现的。
如果你不知道具体怎么操作,可以看上一篇博客:sqlite基础
我的当前数据库信息:
我们现在演示的数据库里面有两个表COMPANY、student,其中COMPANY是一个空表,还没有插入信息;student表中仅有一条Alice的信息。
2.回调函数
在进行C语言实现sqlite操作之前,我们首先得理解一个概念,回调函数。回调函数是一种常见的编程技术,用于在异步程序中处理结果或事件。当执行某个操作时,通常需要等待该操作完成后才能继续执行下一步。在这种情况下,可以将回调函数传递给该操作,以便在操作完成时自动调用该函数。
是不是你还一头雾水,我们先了解程序执行两种方式,同步执行和异步执行。同步执行没什么好说的,即程序从上到下一行一行的顺序执行,但是如果某个进程有许多线程,又必须等某一线程执行,主线程才能继续进行时,如果是同步方式就要一直等待这个需要线程执行完,很容易时间长造成阻塞。这里我们就用了异步执行的方式,异步方式是指在程序运行过程中,某个操作需要花费一定的时间才能完成,而在等待这个操作完成之前,程序会继续执行后面的代码。当这个操作完成后,程序会自动调用相应的回调函数来处理结果。
现在应该明白回调函数的作用了吧,再继续理解,它既然是处理某个线程或操作的处理结果,怎么处理,是不是要定义一个函数来对结果进行处理,所以回调函数是一种在编程中常见的技术,它允许您将一个函数作为参数传递给另一个函数,以便在需要时执行该函数。
他的存在形式是什么呢,其实回调函数严格来说就是一个普通函数,就是处理某个操作结果的函数,它自己可以作为一个参数被操作函数调用而已。举个例子好理解:
#include <stdio.h>
// 回调函数类型定义
typedef void (*Callback)(int);
// 执行计算任务的函数
void calculate(int a, int b, Callback callback) {
int result = a + b;
// 调用回调函数,将结果传递给它
callback(result);
}
// 回调函数的实现
void printResult(int result) {
printf("The result is: %d\n", result);
}
int main() {
// 调用 calculate 函数并传入回调函数
calculate(1, 2, printResult);
return 0;
}
这里我们又一个calculate函数,假设进程程序特别长,在进行calculate操作之后还有其他操作,就可以使用回调函数的编程技术,即本例中把回调函数printResult作为一个参数可以通过calculate引入,这样不需要等他计算结果出来主线程就可以进行后面的操作,等calculate函数把结果计算出来自己调用printResult来打印输出。
有的人说,我为什么要通过函数指针导入,在一个函数内部本身就可以调用另一个函数嘛,这样确实可以,但这样就变成了同步执行方式,它必须等a+b计算结果出来后才会执行printResult函数,如果a+b计算结果没出来,程序就一直卡在这里。
3.函数指针
知道回调函数之后,你就知道回调函数可以作为参数导入,那直接整个函数作为参数导入吗,它其实是一个函数指针来代替引入。
函数指针是什么,顾名思义,就是一个指向函数的指针,只不过他和平时指针的定义方式不同而已。例如void (*Callback)(int)
这段代码的意思就是定义了一个回调函数类型 Callback
,它表示一个以整型参数为输入、无返回值的函数指针类型。(左边返回值,右边输入)
那么typedef void (*Callback)(int)
这行代码的作用,其实是将 void (*Callback)(int)
取一个别名 Callback
,使其可以被当成一个新的数据类型来使用。这样,在程序中可以直接声明 Callback
类型的变量,而不需要再写一长串复杂的函数指针声明。
比如上面例子中写成Callback callback
,而不是写成void (*Callback)(int) callback
。
4.C语言创建表
源代码:
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
//回调函数
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
/*打开数据库*/
rc = sqlite3_open("D:\\softwore work\\db work\\text.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stdout, "Opened database successfully\n");
}
/* 创建表 */
sql = "CREATE TABLE friend(" \
"id INT PRIMARY KEY NOT NULL," \
"name TEXT NOT NULL," \
"age INT NOT NULL," \
"address CHAR(50)," \
"salary REAL );";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); //执行上面的sql语句
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg); //释放内存函数,释放zErrMsg对应的内存空间
}else{
fprintf(stdout, "Table created successfully\n");
}
sqlite3_close(db);
return 0;
}
这里面你理解上面知识点就好理解了,补充两点:
-
反斜杠 “” 字符在许多编程语言中,包括 C 和其派生语言如 C++ 中用于指示一个语句延续到下一行。这被称为行继续字符。每行末尾的反斜杠用于连接(合并)多行字符串以形成单个字符串。这样可以通过将长行分成更小的块来使代码更易于阅读。如果没有反斜杠,则 SQL 语句会被视为多个独立的字符串,在执行代码时会导致语法错误。
-
回调函数:本例的回调函数,通常用于 SQLite 数据库操作中的查询操作。
它的参数包括:
- void *NotUsed:这是一个不使用的指针,通常可以忽略。
- int argc:这是一个整数,表示查询结果集的列数。
- char **argv:这是一个字符数组指针,它包含每个查询结果的值。每个元素都是一个字符串,存储了对应列的值。
- char **azColName:这是一个字符数组指针,它包含每个查询结果的列名。每个元素都是一个字符串,存储了对应列的名称。
在这个回调函数中,它遍历了所有的查询结果,并打印输出了每个结果的列名和对应的值。最后返回0表示操作成功完成。这个回调函数常用于 SQLite 的查询操作中,在执行 select 语句时,SQLite 将结果逐行传递给该回调函数处理。(进行其他操作时,程序执行会很快,一般不会使用到回调函数)
5.演示结果
利用命令端口,可以看到在此基础上,我们成功建立一个friend的表。
四.其他操作
是不是理解上面的知识了,理解上面的知识后你应该就知道怎么使用C语言实现sqlite的其他操做了。
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
/* Open database */
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "INSERT INTO friend " \
"VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
"VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " \
"VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
"VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Records created successfully\n");
}
sqlite3_close(db);
return 0;
}
例如本例修改后就完成了INSERT语句的操作。
五.Python sqlite3 模块 API
-
connect(database[, timeout, isolation_level, detect_types, factory, cached_statements])
打开数据库连接,并返回一个连接对象。其中:
database
:要连接的数据库文件名。timeout
:超时时间,默认为5.0
秒。isolation_level
:事务隔离级别,默认为None
。detect_types
:是否自动检测数据类型,默认为0
(不检测)。factory
:用于创建游标对象的类。默认为None
,表示使用内置的游标类。cached_statements
:是否缓存 SQL 语句,默认为100
。
-
Cursor()
创建一个游标对象,用于执行 SQL 命令并管理结果集。
-
execute(sql[, parameters])
执行 SQL 命令,并将参数传递给 SQL 命令中的占位符。其中:
sql
:要执行的 SQL 命令。parameters
:可选参数,用于替换 SQL 命令中的占位符。
-
fetchone()
获取查询结果集中的下一行数据。
-
fetchmany([size])
获取查询结果集中的多行数据,最多返回
size
行。如果未指定size
,则默认为Cursor.arraysize
。 -
fetchall()
获取查询结果集中的所有行数据。
-
commit()
提交当前事务。
-
rollback()
回滚当前事务。
-
close()
关闭游标对象和数据库连接。
在python中链接数据库并实现创建表的操作:
import sqlite3
conn = sqlite3.connect('D:\\softwore work\\db work\\text.db')
print ("数据库打开成功")
c = conn.cursor()
c.execute('''CREATE TABLE classmate
(ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL);''')
print ("数据表创建成功")
conn.commit()
conn.close()
六.情况说明
懂了之后,其实操作并不难,python链接相对来说比C语言简单。