SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。使用时只需要添加sqlite3.h和sqlite3.c文件,这里放在一个sqlite3目录下,为调用方便,写一个封装文件db.c。首先当然是打开数据库函数:

static sqlite3 *sql_db = NULL;

int open_db()
{
	if (NULL == sql_db)
	{
		return sqlite3_open("./test.db", &sql_db);
	}
	return SQLITE_OK;
}

为了调用方便将sql_db设置为全局变量,为空时需要打开数据库,sqlite3_open函数负责打开test.db,如果没有这个文件就创建一个空的test.db文件。有了打开数据库,当然还得有关闭数据库:

void close_db()
{
	if (NULL != sql_db)
		sqlite3_close(sql_db);
}

这里创建一个TAB_CONFIG表进行测试:

int ret;
char sql[1024] = {0};

strcpy(sql, "create table TAB_CONFIG(CON_ADDR integer, CON_NO integer,CON_Info varchar(20));");
ret = sqlite3_exec(sql_db, sql, NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
	printf("CREATE table TAB_CONFIG error!\n");
}

执行完这个命令,test.db数据库里面已经有了张空表:
空数据库
下面为这个表插入一条数据:

sprintf(sql, "insert into TAB_CONFIG(CON_ADDR,CON_NO,CON_Info) values(1, 20,'%s')", "Hello world");
ret = db_exec(sql);
if (ret != SQLITE_OK)
{
	printf("Table TAB_CONFIG insert data error!\n");
}

再次打开数据库来看:
默认表
表里面已经有数据了,但是我们的程序不能每次执行都创建这个表并插入默认数据的。为了程序更加智能化,我们需要首先判断表是否存在,如果不存在再创建表,为此写一个查看表是否存在的函数:

int check_table_isexist(char *table_name)
{
	int ret;
	char sql[1024];
	char **sel_ret;
	int row, col;
	char *err = NULL;
	
	ret = open_db();
	if (ret != SQLITE_OK)
	{
		printf("open db error\n");
		return -1;
	}
	
	sprintf(sql, "SELECT COUNT(*) FROM sqlite_master where type='table' and name='%s'", table_name);
	if (SQLITE_OK != db_get_table(sql, &sel_ret, &row, &col, &err))
	{
		printf("check table %s error\n", table_name);
		return -2;
	}
	
	if (row > 0)
	{
		int count = atoi(sel_ret[col]);
		sqlite3_free_table(sel_ret);
		return count;
	}
	
	sqlite3_free_table(sel_ret);
	return 0;
}

注意读表操作后记得调用sqlite3_free_table释放资源,之后我们创建表的函数也要修改下:

static int create_db()
{
	int ret;
	char sql[1024] = {0};
	
	ret = open_db();
	if(ret != SQLITE_OK)
	{
		printf("open db error\n");
		return -1;
	}
	
	// 检查表是否存在
	if (check_table_isexist("TAB_CONFIG"))
	{
		printf("table POS_CONFIG has exist!\n");
		return 0;
	}
	// 创建POS_CONFIG表
	strcpy(sql, "create table TAB_CONFIG(CON_ADDR integer,CON_NO integer,CON_Info varchar(20));");
	ret = sqlite3_exec(sql_db, sql, NULL,NULL,NULL);
	if(ret != SQLITE_OK)
	{
		printf("CREATE table TAB_CONFIG error!\n");
		return -2;
	}
	
	// 插入默认数据
	sprintf(sql, "insert into TAB_CONFIG(CON_ADDR,CON_NO,CON_Info) values(1, 20,'%s')", "Hello world");
	ret = db_exec(sql);
	if (ret != SQLITE_OK)
	{
		printf("Table TAB_CONFIG insert data error!\n");
		return -3;
	}
	return 0;
}

再写一个数据库初始化的封装函数:

int init_db()
{
	if (SQLITE_OK == open_db())
		return create_db();
	
	return -1;
}

在db.h头文件中将这些函数导出:

#ifndef DB_H
#define DB_H

#include "sqlite3.h"

int init_db();
void close_db();

#endif

在main.c的主程序中写一个读取表的测试:

#include <stdio.h>
#include <string.h>

#include "db.h"

// 读取配置文件
int load_config()
{
	int ret = 0;
	char sql[200] = {0}; 
	
	char **sel_ret; 
	int row, col; 
	char *err = NULL;
	
	strcpy(sql, "select CON_ADDR,CON_NO,CON_Info from TAB_CONFIG");
	ret = sqlite3_get_table(sql, &sel_ret, &row, &col, &err);
	if(ret == SQLITE_OK)
	{
		if(row > 0)        // 有数据
		{
			int dev_addr = atoi(sel_ret[col]);
			int num = atoi(sel_ret[col+1]);
			
			char info[20] = {0};
			strcpy(info, sel_ret[col+2]);
			
			printf("Read TAB_CONFIG data:\n");
			printf("dev_addr=%d, num=%d, info=%s\n", dev_addr, num, info);
		}
		else
		{
			printf("@@Table TAB_CONFIG no data!\n");
		}
	}
	else
	{
		printf("@@Read config param error!\n");
	}
	return ret;
}

int main(int argc,char* argv[])
{
	if (init_db()
{
printf("database init failed!\n");
	return -1;
}
	load_config();

	sleep(1);
	close_db();

	printf("programme has exit 0\n");
	return 0;
}

为了程序在Linux系统下编译,得手动写个Makefile文件:

sqlite_test: sqlite3.o db.o main.o
	gcc -o sqlite_test db.o main.o ./sqlite3/sqlite3.o -lpthread -ldl -lm 

sqlite3.o: ./sqlite3/sqlite3.c
	gcc -c ./sqlite3/sqlite3.c -o ./sqlite3/sqlite3.o
	
db.o: db.c db.h ./sqlite3/sqlite3.h
	gcc -c db.c -o db.o -I ./sqlite3
	
main.o: main.c main.h ./sqlite3/sqlite3.h
	gcc -c main.c -o main.o -I ./sqlite3

.PHONY: clean
clean:
	rm -rf *.o ./sqlite3/*.o *~ sqlite_test

Makefile具体规则这里就不介绍了,但要注意文件目录的结构和依赖关系,因为程序的目录结构如下:
目录结构
所以编译sqlite3时要写全目录./sqlite3/sqlite3.o,而且引用sqlite3.h时也要写全目录./sqlite3/sqlite3.h。如果是嵌入式Linux使用的话,需要把Makefile中的所有gcc替换为arm-linux-gcc即可,但前提是得先定义交叉编译器的环境变量,为保险起见,编译前查看一下版本信息:
交叉编译器
这样说明交叉编译器的环境变量设置成功了。还有个问题,PC和嵌入式Linux编译总得切换Makefile,能不能写一个Makefile文件呢?答案是肯定的,仿照嵌入式惯例,只需定义一个编译变量CC,只需make时给它赋值即可:
CC环境变量
默认是gcc,如果给ARCH赋值arm的话,CC变量就变为arm-linux-gcc:
编译参数
这下好了Makefile文件,可以编译两种结果了,运行一下吧,执行结果如下:
执行结果
从打印信息看,说明读取表数据的内容是正确的了。

Logo

快速构建 Web 应用程序

更多推荐