C+sqlite笔记(1)

0. 前言

最近小蕊同学工作中遇到了在后端处理时调用sqlite的问题,于是做一点简单的总结。

 

1. 安装

sqlite不需要进行复杂的安装,但是为了后续项目需要,可以将源码先编译成静态链接库。

具体细节可以参照[1]中作者所给出的步骤,在这里只做简单的总结。

1.1

首先是在官网[2]中下载sqlite-amalgamation-3290000.zip (Source code), sqlite-dll-win64-x64-3290000.zip (Precompiled for windows) , sqlite-tools-win32-x86-3290000.zip

amalgamation是源码,稍后编译为静态链接库

sqlite-dll 是预编译的动态链接库

sqlite-tools 是预编译的数据库操作工具,如果只需要在dos窗口下用SQL简易操作,则仅需要下载使用这个,我们的目标是在项目中(based on C)使用SQL来操作,因此暂时先将三个文件一块儿下载了。

1.2

下载完毕后,在VS2017中建立一个项目,用来编译静态库。

新建项目 --> Visual C++ --> Windows 桌面 --> 静态库或者动态库

然后将刚刚下载的sqlite.c, sqlite.h, sqlite.dll, sqlite.def 拷贝到项目目录下再添加至项目中去(其实好像dll没啥用在这里)

编译那儿选择x64(根据需求来)

然后选择

属性 --> C/C++ --> 预编译头 --> 不使用预编译头

属性 --> 常规 --> 配置类型 --> 静态库(.lib)

搞定后,在主界面选择 生成 --> 生成sqlite(U)

 

2. SQL基本语句

这里总结的不全面,基本上是小蕊同学工作上遇到的,都挺基础。可以直接从刚刚下载的tool包里打开sqlite.exe,在dos窗口下open一个数据库,“.open test.db”(不存在就是创建数据库)


create table NAME

 (ID int primary key not null,

 NAME varchar(10) not null,

 X int,Y int,Z int);


insert into TABLE values(X1,X2,X3,X4,X5);


select ID, NAME from TABLE

where XXX > XXX and YYY < YYY;


update TABLE

set XXX=xxx, YYY=yyy where ID = ZZZ;


delete from TABLE where ID = ZZZ;


select * from TABLE

order by XXX ASC|DESC;


比较复杂的语句暂时没有遇到,时刻记住select 返回的是一张表就行了,这样就不怕select嵌套啦

 

3. C语言里调用

3.1 常用的函数与流程

在incude后加载lib

#pragma comment(lib, "sqlite_compile_LIB.lib")

打开/关闭数据库(不存在就是创建)

sqlite3 *db = NULL;

int rc = sqlite3_open("test.db", &db);

sqlite3_close(db);

直接执行语句,在db中执行SQL_str的内容,就是SQL语句啦

rc = sqlite3_exec(db, SQL_str, NULL, NULL, NULL);

事务处理:

在sqlite中,若直接执行某一语句(例如INSERT),会默认为一次事务: begin transaction --> insert --> commit transaction

这样是非常消耗时间的,在批处理中,我们将多次操作显式地整合为一次事务:

例如:

rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);

for i=1-->100000

         sqlite3_exec(XXXX);

rc = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);

然而,当我们调用sqlite3_exec函数时,它每一次都会编译一遍SQL_str中的SQL语句,往往这些语句时重复的

例如重复地做insert到某一张table的操作。 大量的重复编译会消耗60%左右的时间。

因此,我们可以采用预编译(绑定bind)来实现只编译一次,重复使用的操作

rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);

sqlite3_stmt *stmt; // stmt = 'statement'

const char* sql = "INSERT INTO STUDENTS VALUES(?,?,?,?)"; 

sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, 0); //预编译,现在 stmt就代表"INSERT INTO STUDENTS VALUES(?,?,?,?)"

for i=1-->1000000

       sqlite3_reset(stmt);

       sqlite3_bind_int/sqlite3_bind_text/ ... ...

       rc = sqlite3_step(stmt);

sqlite3_finalize(stmt);

rc = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);

 

3.2 例子

新建一个项目,将刚刚编译的.lib, .h, .c, .dll 一股脑的导入进去,也设置为x64,不预编译头

//#include <iostream>
#include "sqlite3.h"
#pragma comment(lib, "sqlite_compile_DLL.lib")
#include <stdio.h>
#include<time.h>
#include<string.h>

void test_is_install()
{
	sqlite3 *db = NULL;
	char *error_msg = NULL;
	int rc = sqlite3_open("test.db", &db);


	if (rc)
	{
		printf("SQL error: %s \n", sqlite3_errmsg(db));
	}
	else
	{
		printf("db is opened \n");
	}

	rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "CREATE TABLE STUDENTS(NUMBER VARCHAR(10), NAME VARCHAR(10), SEX VARCHAR(6), AGE VARCHAR(3));", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00001', 'SUE', 'FAMALE', '10');", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00002', 'SANDY', 'MALE', '11');", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00003', 'TOMMY', 'MALE', '11');", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00004', 'SALLY', 'FAMALE', '13');", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00005', 'SODA', 'MALE', '8');", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00006', 'MARY', 'FAMALE', '14');", NULL, NULL, NULL);

	rc = sqlite3_exec(db, "SELECT STUDENTS.* FROM STUDENTS WHERE SEX='MALE';", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);

	printf("error code: %d \n", rc);
	printf("error msg: %s \n", error_msg);
	sqlite3_close(db);
}

void transaction_batch_insert()
{
	// 初始化
	sqlite3 *db = NULL;
	char *error_msg = NULL;
	int rc = sqlite3_open("batch_insert_using_transaction.db", &db); //打开、创建数据库
	sqlite3_exec(db, "PRAGMA synchronous = OFF; ", 0, 0, 0); 

	if (rc)
	{
		printf("SQL error: %s \n", sqlite3_errmsg(db));
	}
	else
	{
		printf("db is opened \n");
	}
	int batch = 30000;
	clock_t start, end;

	start = clock(); //计时开始

	//开启事务(Transaction)
	rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
	//创建表格 Students
	rc = sqlite3_exec(db, "CREATE TABLE STUDENTS(NUMBER VARCHAR(10), NAME VARCHAR(10), SEX VARCHAR(6), AGE VARCHAR(3));", NULL, NULL, NULL);
	for (int i = 1; i <= batch; i++) //30000次
	{
		//逐条插入数据
		rc = sqlite3_exec(db, "INSERT INTO STUDENTS VALUES('00001', 'SUE', 'FAMALE', '10');", NULL, NULL, NULL);
	}
	//提交事务(Transaction)
	rc = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);
	end = clock();
	printf("time=%f\n", (double)(end - start) / 1); //CLOCKS_PER_SEC
	printf("time=%f\n", (double)(end - start) / CLOCKS_PER_SEC);
	sqlite3_close(db);
}

void precompile_insert()
{
	/* 1. 使用上述transaction_batch_insert()函数的事务处理机制
	   2. 将复用的SQL语句预编译,以达到不用重复编译的目的
	*/

	sqlite3 *db = NULL;
	char *error_msg = NULL;
	int rc = sqlite3_open("batch_insert_using_precompile.db", &db);
	//sqlite3_exec(db, "PRAGMA synchronous = OFF; ", 0, 0, 0);

	if (rc)
	{
		printf("SQL error: %s \n", sqlite3_errmsg(db));
	}
	else
	{
		printf("db is opened \n");
	}
	int batch = 3;
	clock_t start, end;
	start = clock();
	rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
	rc = sqlite3_exec(db, "CREATE TABLE STUDENTS(NUMBER VARCHAR(10), NAME VARCHAR(10), SEX VARCHAR(6), AGE VARCHAR(3));", NULL, NULL, NULL);
	
	
	sqlite3_stmt *stmt; // stmt = 'statement'
	const char* sql = "INSERT INTO STUDENTS VALUES(?,?,?,?)"; 
	sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, 0); //预编译,现在 stmt就代表"INSERT INTO STUDENTS VALUES(?,?,?,?)" 啦

	for (int i = 1; i <= batch; i++)
	{
		sqlite3_reset(stmt);
		rc = sqlite3_step(stmt);
		printf("rc=%d \n", rc);
		sqlite3_bind_text(stmt, 1, "00001", 6, NULL); 
		sqlite3_bind_text(stmt, 2, "Sue", 4, NULL); 
		sqlite3_bind_text(stmt, 3, "F", 2, NULL); 
		sqlite3_bind_text(stmt, 4, "12", 3, NULL);
		rc = sqlite3_step(stmt);
		printf("rc=%d \n", rc);
	}
	sqlite3_finalize(stmt);
	rc = sqlite3_exec(db, "COMMIT TRANSACTION;", NULL, NULL, NULL);
	
	
	end = clock();
	printf("time=%f\n", (double)(end - start) / 1); //CLOCKS_PER_SEC
	printf("time=%f\n", (double)(end - start) / CLOCKS_PER_SEC);

	printf("error code: %d \n", rc);
	printf("error msg: %s \n", error_msg);
	sqlite3_close(db);
}

int main()
{
	//transaction_batch_insert(); //400ms
	precompile_insert(); //192.6ms
	return 0;
}

 

4. Reference

[1] https://blog.csdn.net/jiangwei0910410003/article/details/79435074

[2] https://www.sqlite.org/download.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值