使用步骤
1. 引入头文件:在工程的 Build Phases 下将要用到的 frameworks 和 libraries 添加。下图中我已经将要用的 sqlite3 添加到工程。
2. 指定数据库存储路径:数据库一般都是存储在沙盒根目录下地 Documents 文件夹下,在指定路径的时候,要将数据库的名称也写上
NSString *sandBox = NSHomeDirectory(); NSString *filePath = [sandBox stringByAppendingPathComponent:@"Documents/db_student.sqlite"]; // 创建的数据库名是 db_student.sqlite
3.打开数据库
3.1 首先将 OC 的路径字符串转化为 C 的字符串
const char * path = [filePath UTF8String];
3.2 打开数据库
sqlite3_open(path, &_db);
需要知道的是这句代码有两个作用:
1)如果数据库不存在,则创建数据库,然后打开;
2)如果数据库已经存在,则直接打开数据库。
int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ );
这是这句代码的函数声明:从中可以看到
第一个参数要求的是 数据库的文件名,并且是经过 UTF-8 转化过的 C 字符串;
第二个参数要求的是 sqlite3 类型的双指针,所以传递过来的是一个地址指针;
最后一点:如果成功打开数据库,则返回一个值 SQLITE_OK
#define SQLITE_OK 0 /* Successful result */
4.创建表
4.1 创建表的 sql 语句:注意是 C 语言的字符串而不是 OC 类型的字符串
const char *sql = "create table if not exists tb_student (id integer primary key,sex boolean,name text)";
4.2 执行 DDL 语句,只有是 DDL 语句时才调用 exec 函数
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg); /* 第一个参数:数据库的变量,一个已经打开i数据库 第二个参数:创建表的语句 第三个参数:回调函数,即语句执行完要执行的函数,通常填写 nil 第四个参数:回调函数的第一个参数;通常填 nil 第五个参数:错误信息;可以填 nil;注意是双指针 */ sqlite3_exec(_db, createSql, NULL, NULL,NULL); //所以创建表的语句可以这样写 这句代码同样有个返回值,返回 SQLITE_OK 表示表成功创建。
5.对数据表进行增、删、改、查的操作
5.1 有占位符的 sql 语句
添加 insert into tb_student (name, sex) values (?, ?);
1) 请不要被语句里的 ? 给吓到了,在这里它的作用是占位符的作用,表示这里需要一个值,而这个值不是给定的,而是一个不确定值,例如可以根据文本框获得。
当然了,如果直接使用这种语句操作数据表,那是万万不能的,为啥丫,人家不认识你呗,也许你就说了,那我直接写成确定值,这样总可以吧!答案依然还是不行,这个我也觉得很坑哪([email protected][email protected]=)
那么要怎么办呢 —— 将 sql 语句转化为 sqlite3_stmt 类型(现在都一家人了,总不能还不待见我吧)
sqlite3_stmt * stmt = nil; sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL) //不要小看这两句代码:把字符串类型的 sql 语句,转化为 stmt 类型;只有转化后,才能把问号(?)替换为对应的数据,注意不管 sql 语句里面有没有问号,都要进行转化成这种 stmt 类型
下面这个 C 函数就是上面第二句代码的原型
/* 第一个参数:数据库变量 第二个参数:sql语句 第三个参数:字符串的长度;-1表示系统计算长度; 第四个参数:语句转化之后的存储位置的指针; 第五个参数:超出指定长度的数据的存放位置;通常填null; */ int sqlite3_prepare_v2(sqlite3 *db,const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
2)接下来的共走就是将语句里面的 ?给替换掉了:这个就要根据你的字段类型来决定使用哪个方法了,如果是字符串类型(即 text 类型), 就使用函数
/* 第一个参数:stmt结构 第二个参数:替换哪一个问号;从1开始; 第三个参数:替换的内容 第四个参数:字符串的长度,- 1 表示系统计算长度 第五个参数:回调函数;通常写null */ int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*))
有返回值 SQLITE_OK,表示转化成功
则调用的时候
sqlite3_bind_text(stmt, 1, name, -1, NULL); // name 是通过文本框获取的内容
如果是 int 类型或 boolean 类型则简单多了
sqlite3_bind_int(stmt, 2, sex); // sex 是同过文本框获得的内容
3)执行 sqlite3_step(stmt)
执行成功的时候返回 SQLITE_DONE,所以可以通过返回值来判断语句是否成功执行
4)当插入的动作执行完成的时候,不要忘记将 stmt 销毁
sqlite3_finalize(stmt);
5)关闭数据库
插入完成,不再进行其他操作时,关闭数据库
sqlite3_close(_db);
5.2 没有占位符的查询语句
即使没有 sql 语句中没有占位符,也要将 sqll 语句转化为 stmt 类型
5.3 查询语句
查询语句有两个不同的地方
1)查询成功的返回值不同 SQLITE_ROW
2)运行的机制也有所不同:在将表中所有数据遍历完成之前,一直在进行查询操作,每查询到一条符合条件的记录,就返回一个 SQLITE_ROW,所以可以用这个特性将表中符合条件的数据都取出来。
while (sqlite3_step(stmt) == SQLITE_ROW) { /* 第一个参数:stmt 第二个参数:取哪一列的值 ;从0开始 */ int ID = sqlite3_column_int(stmt, 0); int sex = sqlite3_column_int(stmt, 2); const unsigned char *cName = sqlite3_column_text(stmt, 1); NSString *name = nil; if (cName != NULL) { name = [NSString stringWithUTF8String:(const char *)cName]; } NSLog(@"_____ID: %d ____name: %@ _____ sex: %d", ID, name, sex); }