您的位置:首页 > 数据库

sqlite数据库的基本操作

2017-06-22 22:02 253 查看
今天来聊一聊sqlite数据库的一些基本操作, 之前一直用的是FMDB来操作数据库的, 但是也想对sqlite本身也做一个了解, 那我们就来一起学习一下.

sqlite数据库是一种轻量级数据库,被集成到用户程序中, 占用资源非常的低,在嵌入式设备中,占用内存很低而查询效率很高,因此广泛应用在各种移动客户端中;

简单,轻巧的足够小(C语言API ,4.43M)

快(比大部分的普通数据库都快)

支持的数据库大小至2TB,所以注定了它是一个跨平台利器,在Android与iOS下均能使用,而且完全可以写出通用的代码,方便我们移植。最后一个重要的原因就是原生的使用也是相当简单

Demo的操作环境: Xcode 8.3.3

1. 导入

一图流:



忽略我的警告… :P

然后在你需要使用sqlite3的地方导入头文件

#import <sqlite3.h>


喏, 然后就可以愉快的开始使用了~

2. 我想打开一个数据库!

下面就是sqlite3定义的打开数据库的方法:

int sqlite3_open(
const char *filename,   /* Database filename (UTF-8) */
sqlite3 **ppDb          /* OUT: SQLite db handle */
);


BTW: 我能说第一次我看到这个方法的时候以为是要手动写的, 自己定义了一套么.. :(

上面第一个参数就是数据库所存放的路径,如果有就直接用, 如果路径下没有数据库文件则系统会在此路径下创建一个数据库。至于第二个参数则是数据库的句柄引用,但此函数调用成功后此句柄将会保存打开数据库的句柄,此句柄在往后的数据库操作中需要用到。因此,可如下方式调用:

NSString *path = [NSString stringWithFormat:@"%@/Documents/demo.db",NSHomeDirectory()];
if (sqlite3_open([path UTF8String], &_dbHandle)==SQLITE_OK) {
NSLog(@"打开数据库成功!");
}


来解释一下句柄:

句柄在很多地方我们见到过,最常见的就是文件的句柄,我们要操纵一个文件,我们就要取得一个文件的句柄。句柄是个什么东西?其实很简单,句柄是一个东西的描述,他被定义为一个结构体,这个结构体可能会包含要描述的东西的具体信息,比如位置、大小、类型等等。我们有了这个描述信息我们就能去找到这个东西,然后操纵它。一句话:句柄是物体的描述结构体

咱还可以理解为“把手” : 虽然你握住的只是把手,却能拉动整扇门,而且你根本不用在意那门长什么样子, 一扇门如果有多个把手,被不同的人(进程)握住,门往哪儿走就不好说了…

这是我定义的一个句柄:

static sqlite3 *dbHandle;


3. 关闭数据库!

既然有打开数据库,那么就肯定有关闭数据库的操作了,我们要养成良好的习惯,当需要使用数据库的时候就执行sqlite3_open来打开数据库,等使用完数据库后就调用sqlite3_close函数来对数据库进行关闭。关于sqlite3_close函数声明如下:

int sqlite3_close(sqlite3 *);


关闭的时候把我们定义的句柄传入数据库即可对数据库进行关闭。调用方式如下:

if (sqlite3_close(_dbHandle)==SQLITE_OK) {
NSLog(@"关闭数据库成功!");
}else{
NSLog(@"error %s",sqlite3_errmsg(_dbHandle));
}


4. 数据库的两种基本操作

4.1 sqlite3_exec函数

常用的有两种方式可以操作数据库中的数据和调整结构, 第一种就是sqlite3_exec函数,这种方法一般用在增、删、改。这个函数不适合来查询数据库, 后面我们再介绍查询数据库的方法. 先来看看此方法的声明:

int sqlite3_exec(
sqlite3*,                                  /* An open database 这是我们打开数据库的句柄*/
const char *sql,                           /* SQL to be evaluated 待执行的SQL语句*/
int (*callback)(void*,int,char**,char**),  /* Callback function 回调函数,有固定的格式,你可以自己实现*/
void *,                                    /* 1st argument to callback 回调函数的第一个参数*/
char **errmsg                              /* Error msg written here 如果方法执行后存在异常,那么这个参数保存的就是错误的描述信息*/
);


4.2 创建数据表

要想让数据库能够存储数据,那就必须得创建一个数据表才能进行数据操作。而数据表是可以包含不同的数据字段,这些字段可以指定不同的数据类型,存储不同的数据。我们建表时可以根据需要进行创建。下面的代码创建了一个叫做persons的数据表,其中包含了3个字段id、name和age. (如果对SQL语句不太熟悉的朋友可以参考相关方面资料), 写个实例来演示上面的sqlite3_exec函数:

-(void)createTable
{
//因为sqlite3是C写的,所以传入的时候,sqlite语句要用C的形式传入,如果用NSString *createString = ***; 这种形式会报错
const char *createString = "create table if not exists persons (id integer primary key autoincrement, name varchar(256), age integer)";
char *errorMsg;
BOOL result = sqlite3_exec(_dbHandle, createString, nil, nil, &errorMsg);
if (result == SQLITE_OK) {
NSLog(@"建表成功!");
}else{
NSLog(@"建表失败!Error:%s",sqlite3_errmsg(_dbHandle)));
}
sqlite3_free(errorMsg);
}


面要注意的一点是,如果你有传入errorMsg参数,那么你必须在执行完sqlite3_exec后,执行sqlite3_free函数来释放errorMsg。否则就会造成内存泄露

有个需要注意的点:

先看两张图:





然后你猜猜会报什么错? ;)

2017-06-22 17:44:53.764 SQLiteDemo[68053:2703014] 打开数据库成功!
2017-06-22 17:44:53.764 SQLiteDemo[68053:2703014] 关闭数据库成功!
2017-06-22 17:44:53.764 SQLiteDemo[68053:2703014] 建表失败!Error:(null)
2017-06-22 17:44:53.764 SQLiteDemo[68053:2703014] 插入数据失败! Error:library routine called out of sequence


不明所以? 一脸蒙蔽? 恩…当时的我就是这个样子的! 为什么是null? 如果出了错都不知道原因是什么… :o

所以我用了第二种sqlite3_errmsg(_dbHandle)来打印错误信息,这是一个报错的函数,所以结果就很清楚了: 库程序调用顺序问题

4.3 增 ! 删 ! 改 !

4.3.1 插入数据

上面的例子创建了一个数据后,那么我们可以往里面插入数据,我们可以使用insert语句将数据插入表中:代码如下所示:

-(void)insertInfo
{
const char *insert = "insert into persons (name,age) values ('阿童木',5)";
char *errorMsg;
BOOL result = sqlite3_exec(_dbHandle, insert, nil, nil, &errorMsg);
if (result == SQLITE_OK) {
NSLog(@"插入数据成功!");
}else{
NSLog(@"插入数据失败! Error:%s",sqlite3_errmsg(_dbHandle));
}
}


打印输出:

2017-06-22 17:39:56.379 SQLiteDemo[67920:2698580] 插入数据成功!


4.3.2 删除数据

删除数据只是SQL语句的语法不同而已,其他都一样, 提供两种删除方式:

delete from persons; //会直接删除所有的数据,但是不会清空自动增长列的标识。
delete from persons where id = 8;  //根据id删除


-(void)deleteInfo
{
const char *delete = "delete from persons where id = 1";

BOOL result = sqlite3_exec(_dbHandle, delete, nil, nil, &errorMsg);

if (result == SQLITE_OK) {
NSLog(@"删除数据成功!");
}else{
NSLog(@"删除数据失败!Error:%s",sqlite3_errmsg(_dbHandle));
}
}


4.3.3 更改数据

同上, 其他都一样

const char *change = "update persons set name = '铁甲小宝' age = '40' where id = 2";


4.4 重点: 查 !

sqlite3_prepare_v2和sqlite3_step函数

我们查询数据库就使用sqlite3_prepare_v2和sqlite3_step两个函数搭配进行操作。其中sqlite3_prepare_v2是一个将SQL语句编译为sqlite内部一个结构体(sqlite3_stmt).该结构体中包含了将要执行的的SQL语句的信息。而sqlite3_step则是让转化后的SQL进行下一步的操作。因此通过这两个函数可以很方便的获取到数据库中的数据。本人建议使用此方式取得记录集。下面是这两个函数的声明:

int sqlite3_prepare_v2(
sqlite3 *db,            /* Database handle  句柄*/
const char *zSql,       /* SQL statement, UTF-8 encoded  SQL语句 */
int nByte,              /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);


第三个参数是用于指定SQL语句最大的长度,如果此参数为负数,则根据第二个参数中的第一个终结符为准作为一条完整的语句。如果为非负数,则以第二个参数的第一个终结符,或者指定的数字为准作为一条完整语句。第四个参数则是调用函数后返回的一个结构体,此结构体包含了相关语句的信息。关于第五个参数是用于指向前一条语句结束位置,一旦指定此参数,则参数指向位置的左边语句将不进行编译解析。

sqlite3_step(sqlite3_stmt *);


传入参数即为准备语句中的结构体对象。

例子:

-(void)searchInfo
{
//创建数组 存数据
NSMutableArray *array = [[NSMutableArray alloc]init];

const char *select = "select * from persons where name = '阿童木'";

//sqlite3_prepare_v2的参数第一个是数据库连接,第二个是sql语句,第三个是这个语句的长度传入-1表示到第一个null终止符为止,第四个是返回一个语句对象,第五个是返回一个指向该sql语句的第一个字节的指针
int result = sqlite3_prepare_v2(_dbHandle, select, -1, &stmt, nil);
if (result == SQLITE_OK) {
// 开始遍历 每调一次sqlite3_step函数,stmt就会指向下一条记录
while (sqlite3_step(stmt) == SQLITE_ROW) {

int ID = sqlite3_column_int(stmt, 0);  // 取出第0列字段的值(int类型的值)
const unsigned char *name = sqlite3_column_text(stmt, 1);  // 取出第1列字段的值(text类型的值)
int age = sqlite3_column_int(stmt, 2);  // 取出第2列字段的值(int类型的值)
//将C字符串转换为OC字符串
NSString *name1 = [[NSString alloc]initWithUTF8String:(const char *)name];
//将model实例化 并把取出来的数据存入model
ZTPerson *p = [[ZTPerson alloc]init];
p.name = name1;
p.age = age;
p.ID = ID;
[array addObject:p];
}
}else{
NSLog(@"查询语句有问题,查询失败!");
}
NSLog(@"%@",array);
}


这就是今天的关于sqlite数据库的内容, 感觉还差点什么, 明天想起来再加进去.

2017年06月22日22:01:38 Reborn_Tai
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息