数据库-SQLite
目录
1.SQLite介绍
2.SQLite特性
3.SQLite使用
3.1.环境准备
3.2.创建数据库文件
3.3.操作数据库
4.API接口
4.1.封装数据库句柄结构体
4.2.数据库句柄初始化
4.3.连接数据库
4.4.创建表 插入数据 修改数据 删除数据
4.5.执行查询语句
4.6.初始化存储查询结果句柄
4.7.获取每一行查询结果
4.8.释放查询结果集
5.完整代码
6.总结
1.SQLite介绍
SQLite 是一个轻量级的关系型数据库管理系统(RDBMS),广泛应用于桌面应用程序、移动设备和小型服务端应用中。它的主要特点是不需要一个独立的数据库服务器,而是通过嵌入到应用程序中运行。SQLite 使用一个简单的数据库文件存储所有数据,因此可以方便地进行数据的传输和备份。它支持 ACID(原子性、一致性、隔离性、持久性)事务,保证数据的可靠性。
2.SQLite特性
优点:不需要配置、数据库文件小、支持跨平台、支持标准 SQL,并且非常适合用于嵌入式系统和低并发的应用。它在移动设备和桌面应用程序中非常流行,尤其是作为本地存储的数据库解决方案。在SQLite中,一个文件可以类似的看成MySQL中的数据库,即一个文件就是一个数据库。
缺点:不适合高并发的应用、对于大规模数据处理可能性能不如 MySQL、PostgreSQL。
3.SQLite使用
3.1.环境准备
需要安装sqlite3相关的安装包,参考ubuntu命令:apt-get install sqlite3 libsqlite3-dev
3.2.创建数据库文件
使用 vim 在任意目录创建一个文件,后缀名没有要求,例如:vim test.sql
3.3.操作数据库
创建好文件之后就可以操作该数据库了,例如:sqlite3 test.sql
之后便可以创建表,然后进行增删改查操作。
4.API接口
4.1.封装数据库句柄结构体
typedef struct _DBHandle {
sqlite3 *db;
sqlite3_stmt *stmt;
char **res;
int column_num;
}DBHandle;
db:sqlite3自带的数据库处理句柄
stmt:sqlite3保存查询句柄
res:用于保存查询结果的每一行
column_num:查询结果的列数
注:此结构体可以根据实际调整,具体为什么要这样实现可以参考MySql的机制。
4.2.数据库句柄初始化
初始化只需要将数据库句柄赋值为0即可。
/* 数据库句柄初始化 */
void db_sqlite_init(DBHandle *db_handle) {
memset(db_handle, 0, sizeof(DBHandle));
return;
}
4.3.连接数据库
连接数据库即打开sqlite3数据库文件的过程,调用sqlite3原生接口。
SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
/* 连接数据库 */
int db_sqlite_connect(DBHandle *db_handle, const char *file_name) {
int result = sqlite3_open(file_name, &db_handle->db);
if (result != SQLITE_OK) {
printf("Can't open database: %s\n", sqlite3_errmsg(db_handle->db));
return DB_FAILED;
}
return DB_SUCCESS;
}
4.4.创建表 插入数据 修改数据 删除数据
创建表 插入数据 修改数据 删除数据不需要获取查询结果,调用sqlite3操作sql语句的接口即可。
SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
/* 创建表 插入数据 修改数据 删除数据 */
int db_sqlite_execute(DBHandle *db_handle, const char *sql) {
char *err_msg = NULL;
int result = sqlite3_exec(db_handle->db, sql, 0, 0, &err_msg);
if (result != SQLITE_OK) {
printf("Failed execute sql, errmsg: %s.", err_msg);
sqlite3_free(err_msg);
return DB_FAILED;
}
return DB_SUCCESS;
}
4.5.执行查询语句
执行查询语句需要传递 stmt 参数,同时调用sqlite3接口sqlite3_prepare_v2
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
/* 执行查询语句 */
int db_sqlite_query(DBHandle *db_handle, const char *sql) {
int result = sqlite3_prepare_v2(db_handle->db, sql, -1, &db_handle->stmt, 0);
if (result != SQLITE_OK) {
printf("Failed to prepare statement: %s\n", sqlite3_errmsg(db_handle->db));
return DB_FAILED;
}
return DB_SUCCESS;
}
4.6.初始化存储查询结果句柄
初始话查询结果句柄 res,其实就是给 res 分配内存空间,用于保存每一行的查询结果。
/* 初始化存储查询结果句柄 */
int db_sqlite_fetch_init(DBHandle *db_handle) {
db_handle->column_num = sqlite3_column_count(db_handle->stmt);
db_handle->res = (char **)malloc(sizeof(char *) * db_handle->column_num );
if (!db_handle->res) {
printf("Failed to malloc memory for db_handle->res.");
return DB_FAILED;
}
memset(db_handle->res, 0, sizeof(char *) * db_handle->column_num );
return DB_SUCCESS;
}
4.7.获取每一行查询结果
获取每一行查询结果,循环调用 sqlite3_step 函数,直到没有数据为止。
注:此处为了方便统一接口,均返回char *(字符串类型),用户根据列属性自行转换。
SQLITE_API int sqlite3_step(sqlite3_stmt*);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
/* 获取每一行查询结果 */
char **db_sqlite_fetch_data(DBHandle *db_handle) {
if (!db_handle->stmt) {
return NULL;
}
if ((sqlite3_step(db_handle->stmt)) == SQLITE_ROW) {
for (int i = 0; i < db_handle->column_num; i++) {
db_handle->res[i] = (char *)sqlite3_column_text(db_handle->stmt, i);
}
return db_handle->res;
}
return NULL;
}
4.8.释放查询结果集
释放查询结果集主要分两部分,一部分是释放申请的 res 内存,另外一部分是释放sqlite3使用的 stmt。
注:为什么要这样设计可以参考MySql实现
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
/* 释放查询结果集 */
void db_sqlite_fetch_free(DBHandle *db_handle) {
if (db_handle->res) {
free(db_handle->res);
}
sqlite3_finalize(db_handle->stmt);
}
5.完整代码
注:编译时需要链接sqlite3动态库
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define DB_FAILED -1
#define DB_SUCCESS 0
#define MAX_SQL_LEN 1024
typedef struct _DBHandle {
sqlite3 *db;
sqlite3_stmt *stmt;
char **res;
int column_num;
}DBHandle;
/* 数据库句柄初始化 */
void db_sqlite_init(DBHandle *db_handle) {
memset(db_handle, 0, sizeof(DBHandle));
return;
}
/* 连接数据库 */
int db_sqlite_connect(DBHandle *db_handle, const char *file_name) {
int result = sqlite3_open(file_name, &db_handle->db);
if (result != SQLITE_OK) {
printf("Can't open database: %s\n", sqlite3_errmsg(db_handle->db));
return DB_FAILED;
}
return DB_SUCCESS;
}
/* 创建表 插入数据 修改数据 删除数据 */
int db_sqlite_execute(DBHandle *db_handle, const char *sql) {
char *err_msg = NULL;
int result = sqlite3_exec(db_handle->db, sql, 0, 0, &err_msg);
if (result != SQLITE_OK) {
printf("Failed execute sql, errmsg: %s.", err_msg);
sqlite3_free(err_msg);
return DB_FAILED;
}
return DB_SUCCESS;
}
/* 插入数据 */
int insert_data(DBHandle *db_handle, const char *name, int age) {
char sql[MAX_SQL_LEN] = {0};
sqlite3_stmt *stmt;
snprintf(sql, (size_t)MAX_SQL_LEN, "INSERT INTO users (name, age) VALUES (\"%s\", %d);", name, age);
printf("sql:%s\n", sql);
return db_sqlite_execute(db_handle, sql);
}
/* 执行查询语句 */
int db_sqlite_query(DBHandle *db_handle, const char *sql) {
int result = sqlite3_prepare_v2(db_handle->db, sql, -1, &db_handle->stmt, 0);
if (result != SQLITE_OK) {
printf("Failed to prepare statement: %s\n", sqlite3_errmsg(db_handle->db));
return DB_FAILED;
}
return DB_SUCCESS;
}
/* 初始化存储查询结果句柄 */
int db_sqlite_fetch_init(DBHandle *db_handle) {
db_handle->column_num = sqlite3_column_count(db_handle->stmt);
db_handle->res = (char **)malloc(sizeof(char *) * db_handle->column_num );
if (!db_handle->res) {
printf("Failed to malloc memory for db_handle->res.");
return DB_FAILED;
}
memset(db_handle->res, 0, sizeof(char *) * db_handle->column_num );
return DB_SUCCESS;
}
/* 获取每一行查询结果 */
char **db_sqlite_fetch_data(DBHandle *db_handle) {
if (!db_handle->stmt) {
return NULL;
}
if ((sqlite3_step(db_handle->stmt)) == SQLITE_ROW) {
for (int i = 0; i < db_handle->column_num; i++) {
db_handle->res[i] = (char *)sqlite3_column_text(db_handle->stmt, i);
}
return db_handle->res;
}
return NULL;
}
/* 释放查询结果集 */
void db_sqlite_fetch_free(DBHandle *db_handle) {
if (db_handle->res) {
free(db_handle->res);
}
sqlite3_finalize(db_handle->stmt);
}
/* 查询users表数据 */
int query_users(DBHandle *db_handle) {
const char *sql = "SELECT * FROM users;";
if (db_sqlite_query(db_handle, sql) != DB_SUCCESS) {
return DB_FAILED;
}
if (db_sqlite_fetch_init(db_handle) != DB_SUCCESS) {
return DB_FAILED;
}
while (db_sqlite_fetch_data(db_handle)) {
printf("ID: %d, Name: %s, Age: %d\n", atoi(db_handle->res[0]), db_handle->res[1], atoi(db_handle->res[2]));
}
db_sqlite_fetch_free(db_handle);
return DB_SUCCESS;
}
/* 更新users表数据 */
int update_users(DBHandle *db_handle, const char *name, int age, int id) {
char sql[MAX_SQL_LEN] = {0};
sqlite3_stmt *stmt;
snprintf(sql, (size_t)MAX_SQL_LEN, "UPDATE users SET name = \"%s\", age = %d WHERE id = %d;", name, age, id);
return db_sqlite_execute(db_handle, sql);
}
/* 删除users表数据 */
int delete_users(DBHandle *db_handle, const char *name) {
char sql[MAX_SQL_LEN] = {0};
sqlite3_stmt *stmt;
snprintf(sql, (size_t)MAX_SQL_LEN, "DELETE FROM users WHERE name = \"%s\";", name);
return db_sqlite_execute(db_handle, sql);
}
int main()
{
DBHandle db_hanle;
db_sqlite_init(&db_hanle);
db_sqlite_connect(&db_hanle, "./test.db");
/* 建表 */
if (db_sqlite_execute(&db_hanle, "CREATE TABLE IF NOT EXISTS users (""id INTEGER PRIMARY KEY AUTOINCREMENT,""name TEXT NOT NULL,""age INTEGER NOT NULL);")) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
/* 插入数据 */
if (insert_data(&db_hanle, "Tom", 25) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
/* 插入数据 */
if (insert_data(&db_hanle, "Jerry", 30) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
printf("Users:\n");
if (query_users(&db_hanle) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
if (update_users(&db_hanle, "Jack", 18, 1) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
printf("\nAfter Update:\n");
if (query_users(&db_hanle) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
if (delete_users(&db_hanle, "Jerry") != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
printf("\nAfter Delete:\n");
if (query_users(&db_hanle) != DB_SUCCESS) {
sqlite3_close(db_hanle.db);
return DB_FAILED;
}
sqlite3_close(db_hanle.db);
return 0;
}
运行结果:
6.总结
SQLite 是一个轻量级的嵌入式关系型数据库管理系统,它不依赖独立的服务器进程,而是直接嵌入到应用程序中。SQLite 通过一个文件存储整个数据库,所有的数据、表、索引和视图都保存在这个文件里。简单、易用、无需配置、占用资源少、支持跨平台。