Sqlite3的基本使用主要是对2个对象(sqlite3、pstmt)和8个方法(open、step、close等)的理解,本教程会以此为提纲作深入的讲解,全文以sqlite3的使用流程作为行文顺序并介绍其相关的一些方法的使用,have fun!

sqlite对象

每一个打开的数据库都使用一个不透明的sqlite对象来表示。其声明非常简单任性,只是使用typedef起了一个别名,如下:

typedef struct sqlite3 sqlite3;

sqlite3_initialize( )

对应的有4个方法:

int sqlite3_initialize(void);
int sqlite3_shutdown(void);
int sqlite3_os_init(void);// 可以忽略,initialize方法中已经根据不同的平台做了实现
int sqlite3_os_end(void);// 可以忽略,initialize方法中已经根据不同的平台做了实现

initialize方法和shutdown方法对应,os_init和os_end对应,在os系统中使用,其意义如下:

  • 构造方法和销毁方法一一对应且只能对一个对象调用一次,调用多次不会做额外操作且无伤害(harmless)
  • 构造方法需要在使用任何其他的sqlite api之前调用(sqlite3_config()方法需要在init之前调用),销毁方法需要在所有连接已经关闭且所有资源被释放的情况下调用
  • init方法线程安全,销毁方法线程不安全,销毁方法只能在一个线程中调用
  • 编译阶段可以设置自动调用初始化方法,但是官方建议手动调用初始化方法,因为以后的发布版本中会逐步使用非自动初始化的模式。许多方法在内部会自动调用初始化方法,比如open方法。如果是非自动初始化的模式,则需要自己手动调用。
  • 不能主动调用os_init和os_end,这两个函数已经被封装在了initialize方法中,会根据平台的不同进行不同的操作

总结:这个方法一般被封装在了open当中,一般不需要主动调用(至少在iOS中使用sqlite3lib库时),是一个不需要重点关注的方法
initialize方法官方文档

sqlite3_open

建立数据库连接的方法。open方法应该有三个:sqlite3_open、sqlite3_open16、sqlite3_open_v2。其中open方法内部调用的就是open_v2方法,只是配置的参数不一样,其区别如下:

方法名 编码方式 第三个参数 第四个参数
sqlite3_open UTF-8 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE NULL对象(默认的sqlite3_vfs对象)
sqlite3_open16 UTF-16 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE NULL对象(默认的sqlite3_vfs对象)
sqlite3_open_v2 UTF-8 可配置 可配置

两个注意点:

  • open方法在建立连接时,无论成功还是失败,都会返回一个指针对象,唯一的例外是当内存不够分配给一个sqlite3对象时,open方法会返回一个NULL。所以,每次open最好判断是否成功,如果失败则主动close掉连接。

  • 对于open_v2第三个参数的配置要求为:必选+可选。必选为
    SQLITE_OPEN_READONLY、SQLITE_OPEN_READWRITE、SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE三个中的一个。可选项为下表中的任意配置,相关的官方文档

sqlite3_open_v2

sqlite3_open_v2方法需要重点关注,其声明如下:

SQLITE_API int sqlite3_open_v2(const char *filename,   /* Database filename (UTF-8) */sqlite3 **ppDb,         /* OUT: SQLite db handle */int flags,              /* Flags */const char *zVfs        /* Name of VFS module to use */
);

参数的意义:
第一个参数:fineName,就是要连接的数据库的文件名地址
第二个参数:sqlite3对象,sqlite3中使用sqlite3对象来表示一个连接
第三个参数:flags,打开数据库时配置的一些参数。下文会具体介绍。
第四个参数:vfs

open_v2可配置的参数:

参数名 使用限制 意义
SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ 只读
SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ 可读可写
SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ 没有则创建
SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ 使用URI模式
SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ ???
SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ 并发模式
SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ 串行模式
SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ 共享缓存模式
SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ 私有缓存模式

总表:Flags For File Open Operations

详细说说第三个参数:

  • 如果第三个参数中设置了SQLITE_OPEN_URI,则第一个参数,也就是filename就会采用URI而不是单纯的文件路劲,具体可参考本文后面的URI部分
  • 第三个参数读写模式是必选项,有三个选项:SQLITE_OPEN_READONLY(只读)、SQLITE_OPEN_READWRITE(可写可读)、SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE(可写可读,没有数据库文件则主动创建)。第三个参数必须是这三个选项中的一个和上表中的其他的参数进行组合。
  • mutex配置是在run-time时期设置sqlite的线程模式
  • cache选项是设置共享缓存,可参考sqlite系列文章第三篇:https://www.jianshu.com/p/f036a947853b

sqlite3_prepare_v2

sqlite3中的open方法的意义:sql的执行需要一个字节码程序。而prepare方法就是将sql语句生成一个二进制的程序等待被执行。另一个角度而言,prepare方法是生成一个 prepared statement对象,而这个对象就代表一个已经被编译成二进制格式的程序。

prepare方法:prepare方法众多,其中sqlite3_prepare是历史遗留方法,不能使用,一般使用sqlite3_prepare_v2方法,其他方法可以参考官方文档

参数的意义:第一第二个参数不做解释。第三个参数为负数时,从第一个字符开始读取到第一个终止符(也就是'\0'),所以为负数时就是指读取sql参数中的所有。为正数时指从第几个char字符开始读取,为0时不读取。pzTail指向被解析的字符串的末尾,一般为null,具体意义可参考官方文档

ppStmt:指向一个已经编译过的prepared statement,用于给将要执行的sql添加参数

以插入的sql为例,具体使用如下:

- (void)sqliteInsert {sqlite3 *sqlite;int result = sqlite3_open_v2(DATABASEPATH, &sqlite, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);if(result != SQLITE_OK) {NSLog(@"error opening!: %d", result);} else {// 无论是否报错,database connection(也就是sqlite3对象)都会被分配内存,需要close来释放掉内存sqlite3_close(sqlite);}// 使用prepare插入NSString *insertSql = @"replace INTO ClientTable (name, no, signature) values ( ?, ?, ?);";sqlite3_stmt *statment;// prepared方法的作用是使用sql生成一个可执行的程序sqlite3_prepare_v2(sqlite, [insertSql UTF8String], -1, &statment, NULL);// 绑定句柄sqlite3_bind_text(statment, 1,[@"测试" UTF8String], -1, NULL);sqlite3_bind_text(statment, 2,[@"01" UTF8String], -1, NULL);sqlite3_bind_text(statment, 3,[@"测试签名" UTF8String], -1, NULL);// step是执行sql语句int errorNo = sqlite3_step(statment);if (errorNo != SQLITE_DONE) {NSLog(@"错误");}sqlite3_finalize(statment);sqlite3_close(sqlite);
}

sqlite3_bind()

bind方法会根据绑定参数的类型分为主要的三种,text表示字符串;blob表示二进制文件,比如图片、音频;double/int/int64等都表示数字。当然还有其他的,比如null,这里不做细说。因为oc中最长使用的是字符串,所以需要重点关注sqlite3_bind_text();

sqlite3_bind_text的参数:

  • 第一个参数:从prepare函数中分配好内存的statement对象
  • 第二个参数:所绑定参数在表中对应的索引
  • 第三个参数:绑定的值
  • 第四个参数:第三个参数需要取到的结尾的偏移量。如果是text的话,传负数代表取到第一个/0终止符,即取所有字符串。可以为正数,代表只取部分,但是如果取到的字符串中有nul,则会出现不可预知的问题。如果是blob类型,该值不能为负数。
    第五个参数:对于blob和text而言,这个参数是处理完成后的回调函数

bind函数的使用:

- (BOOL)insertWithName:(NSString *)name no:(NSString *)no signature:(NSString *)signature {sqlite3 *sqlite;int openFlag = sqlite3_open_v2(DATABASEPATH, &sqlite, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE, NULL);if (openFlag != SQLITE_OK) {NSLog(@"数据库打开失败!");sqlite3_close(sqlite);}NSString *sql = @"replace into ClientTable (name,no,signature) values (?, ?, ?);";sqlite3_stmt *statement;int prepareFlag = sqlite3_prepare_v2(sqlite, [sql UTF8String], -1, &statement, NULL);if (prepareFlag !=SQLITE_OK) {NSLog(@"数据库prepare失败");}sqlite3_bind_text(statement, 1, [name UTF8String], -1, NULL);sqlite3_bind_text(statement, 2, [no UTF8String], -1, NULL);sqlite3_bind_text(statement, 3, [signature UTF8String], -1, NULL);
//    // 获取参数的index,第二个参数怎么传??暂未找到方法
//    int index = sqlite3_bind_parameter_index(statement, "name");int stepFlag = sqlite3_step(statement);if (stepFlag != SQLITE_DONE) {NSLog(@"插入执行失败!");}sqlite3_finalize(statement);sqlite3_close(sqlite);if (stepFlag != SQLITE_DONE) {return NO;} else {return YES;}
}

sqlite3_step()

当sql被prepare、bind完成后,接下来的步骤就是调用sqlite3_step()方法来执行sql语句。执行完step方法后,有三种结果:

  • 报错
    错误号包括busy、misuse等,根据错误号进行处理即可
  • SQLITE_ROW
    执行完成一次但是还有结果需要返回,需要继续调用step方法获取后续的结果
  • SQLITE_DONE
    表示执行完成并已经返回了所有结果

几个注意点

  • 首先出现SQLITE_ROW的时,是有数据返回的情况,也就是执行SELECT语句时。
  • 每执行一次step()方法返回一行数据
  • 必须执行到SQLITE_DONE时才表示所有结果都已经返回,且SQLITE_DONE时不返回数据。

sqlite3_step()使用步骤
代码如下:

- (void)query {sqlite3 *sqlite;NSLog(@"%@",[NSString stringWithUTF8String:DATABASEPATH]);int openFlag = sqlite3_open_v2(DATABASEPATH, &sqlite, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);if (openFlag != SQLITE_OK) {NSLog(@"数据库打开失败!");sqlite3_close(sqlite);}// +0表示将'no'转化成数字进行比较NSString *sql = @"select * from ClientTable where no+0 > ?";sqlite3_stmt *statement;int prepareFlag = sqlite3_prepare_v2(sqlite, [sql UTF8String], -1, &statement, NULL);if (prepareFlag !=SQLITE_OK) {NSLog(@"数据库prepare失败");}// 获取sql中的参数个数int paramCount = sqlite3_bind_parameter_count(statement);//    sqlite3_bind_text(statement, 1, "100", -1, nil);// 绑定int类型的参数sqlite3_bind_int(statement, 1, 100);//    // 执行一次就要获取一次结果,只执行而不使用column获取结果将会导致数据丢失
//    int result = sqlite3_step(statement);while (sqlite3_step(statement) == SQLITE_ROW) {NSUInteger num_cols = (NSUInteger)sqlite3_data_count(statement);int columnCount = sqlite3_data_count(statement);const unsigned char *c1 = sqlite3_column_text(statement, 0);const unsigned char *c2 = sqlite3_column_text(statement, 1);const unsigned char *c3 = sqlite3_column_text(statement, 2);NSLog(@"%s-%s-%s",c1,c2,c3);}sqlite3_finalize(statement);sqlite3_close(sqlite);
}

sqlite3_step()中的结果处理有关的几个方法
sqlite3_bind_parameter_count:获取sql中需要绑定的参数的个数
sqlite3_column_type:获取对应列名的类型,用于动态绑定/获取参数
sqlite3_column_count:获取step执行完毕后的结果行中的列数,用于将数据进行序列化从而输出数据
sqlite3_data_count:和sqlite3_column_count大同小异

sqlite3_finalize()

关闭虚拟机并释放所有由prepare()函数产生的内存

sqlite3_close()

关闭数据库

sqlite3_reset()

用户一般不会多次执行完全相同的sql语句,但是会经常执行格式差不多但是参数不一样的sql语句。按照常规操作,bind后需要finalize对应的statement然后再次sqlite_prepare新的statement。但是sqlite_reset方法的效率是大于等于sqlite_prepare方法的,而sqlite_reset相当于将statement回滚到了最初的状态。所以使用reset可以显著地提高程序的性能表现。

FMDB中正是使用了这个特性,将bind之前的sql语句对应的pstmt存储起来,每次使用之前进行reset,如果没有才创建,代码如下:

if (_shouldCacheStatements && !cachedStmt) {cachedStmt = [[FMStatement alloc] init];[cachedStmt setStatement:pStmt];[self setCachedStatement:cachedStmt forQuery:sql];FMDBRelease(cachedStmt);}if (cachedStmt) {[cachedStmt setUseCount:[cachedStmt useCount] + 1];closeErrorCode = sqlite3_reset(pStmt);} else {/* Finalize the virtual machine. This releases all memory and other** resources allocated by the sqlite3_prepare() call above.*/closeErrorCode = sqlite3_finalize(pStmt);}

备注
1、FMDB中的reset模式默认关闭,可以通过self.db.shouldCacheStatements = YES;来开启pstmt缓存模式
2、在[database close]时会清空所有数据,所以reset的优化效果仅限于一次open-close之内的操作

sqlite3_exec

exec方法是对 sqlite3_prepare_v2()、sqlite3_step()、和 sqlite3_finalize()方法的封装。可以一步到位执行多个sql语句,但是无法绑定参数。使用如下:
注意点:
1、要根据返回值判断是否执行成功,因为执行错误不一定会有errMsg(具体如何使用errMsg??)
2、如果使用了errMsg,那么需要手动调用sqlite_free()方法来释放内存
代码如下:

- (void)createDB {sqlite3 *sqlite;int openFlage = sqlite3_open_v2(DATABASEPATH, &sqlite, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);if (openFlage != SQLITE_OK) {sqlite3_close(sqlite);NSLog(@"数据库打开失败!");}NSLog(@"path:%@",[NSString stringWithUTF8String:DATABASEPATH]);NSString *deleteSql = @"delete from ClientTable";char *err = 0;int deleteFlag = sqlite3_exec(sqlite, [deleteSql UTF8String], NULL, NULL, &err);if (deleteFlag != SQLITE_OK) {NSLog(@"数据库表创建失败!");NSLog(@"%s",err);}NSString *sql = @"CREATE table if not exists ClientTable (name text, no text, signature text,PRIMARY KEY(no));delete from ClientTable";int createFlag = sqlite3_exec(sqlite, [sql UTF8String], NULL, NULL, NULL);if (createFlag != SQLITE_OK) {NSLog(@"数据库表创建失败!");}sqlite3_free(err);int closeFlag = sqlite3_close(sqlite);if (closeFlag != SQLITE_OK) {NSLog(@"close错误");}
}
vfs是什么?


仅vfs可设置的参数(sqlite3_vfs.xOpen方法):

参数名 使用限制 意义
SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ ???
SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ ???
SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ ???
SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ ???
SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ ???
SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ ???
SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ ???
SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ ???
SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ ???
SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ ???

总表:Flags For File Open Operations

URI是什么?

URI:统一资源标识符
URL:统一资源定位符,带访问方式的统一资源标识符
URN:统一资源名

三者关系:URL和URN都是是URI的子集。URN上中加上了对应的访问方式就成了URL。因为是子集,URL、URN都可以叫做URI

例如8985321是一串电话,可以认为是URN,是URN必定是URI了。但是你不用用http协议去访问电话吧?应当使用tel:+0278985321这种方式去访问,所以这里的“tel:+0278985321”就是一个URL,也可以说成是一个URI。类似的还有https:www.baidu.com,其实是访问了服务器中的index.html这种文件,只是代理吧IP处理成了域名,并将端口号等信息进行了封装

sqlite3中的URI

URI说白了就是告诉程序open的是哪个数据库文件,同时sqlite3中可以在URI中添加很多参数,这样就直接省去了在第三个参数中设置的麻烦

开启URI的三种方式:

URI的参数设置:
vfs:vfs设置
mode:设置数据库的打开方式,也就是read、write、create那几个参数
cache:缓存模式,也就是share-cache和private-cache,共享缓存模式
psow:存储介质相关,略
nolock:设置 rollback journal modes模式,参考sqlite3中的文件锁
immutable:布尔值,为yes时代表当前使用的数据库是只读类的媒体文件(例如只读光盘的刻录)。此时程序认为数据库只为以只读的方式打开,所有的锁都会失效。

官方文档:2个对象和8个方法的概览 或者说是 sqlite中的核心接口和对象

For More Essence

iOS数据库的使用(二):sqlite教程相关推荐

  1. Xamarin SQLite教程Xamarin.iOS项目添加引用

    Xamarin SQLite教程Xamarin.iOS项目添加引用 使用直接方式访问SQLite数据库,需要将System.Data和Mono.Data.SQlite库导入到创建的项目中.下面将分别讲 ...

  2. 使用iOS原生sqlite3框架对sqlite数据库进行操作

    摘要: iOS中sqlite3框架可以很好的对sqlite数据库进行支持,通过面向对象的封装,可以更易于开发者使用. 使用iOS原生sqlite3框架对sqlite数据库进行操作 一.引言 sqlit ...

  3. Xamarin SQLite教程数据库访问与生成

    Xamarin SQLite教程数据库访问与生成 在本教程中,我们将讲解如何开发SQLite相关的App.在编写程序前,首先需要做一些准备工作,如了解Xamarin数据库访问方式,添加引用,构建使用库 ...

  4. 【玩转SQLite系列】(二)SQLite创建和打开数据库的三种方式

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53234396 本文出自[DylanAndroid的博客] [玩转SQLite系 ...

  5. [源码、文档、分享] iOS/iPhone学习系列、代码教程(转)

    iOS/iPhone学习系列.代码教程----~~~持续更新中~~~ http://www.devdiv.com/iOS_iPhone-iOS_iPhone%E5%AD%A6%E4%B9%A0%E7% ...

  6. 常用开发工具 之 SQLite 数据库 与 Navicat for SQLite 的下载、安装与简单使用说明

    常用开发工具 之 SQLite 数据库 与 Navicat for SQLite 的下载.安装与简单使用说明 目录 常用开发工具 之 SQLite 数据库 与 Navicat for SQLite 的 ...

  7. android数据库isnull,Android中SQLite数据库知识点总结

    SQLite 数据库简介 SQLite 是一个轻量级数据库,它是D. Richard Hipp建立的公有领域项目,在2000年发布了第一个版本.它的设计目标是嵌入式的,而且占用资源非常低,在内存中只需 ...

  8. 转载-Android数据库高手秘籍(一)——SQLite命令

     原文地址: http://blog.csdn.net/guolin_blog/article/details/38461239 Android数据库高手秘籍(一)--SQLite命令 分类: And ...

  9. mysql windows 管道连接,科技常识:Windows Server 2016 MySQL数据库安装配置详细安装教程...

    今天小编跟大家讲解下有关Windows Server 2016 MySQL数据库安装配置详细安装教程 ,相信小伙伴们对这个话题应该也很关注吧,小编也收集到了有关Windows Server 2016 ...

  10. 图解Sqlite教程2

    图解Sqlite教程 http://blog.csdn.net/bcbobo21cn/article/details/43852553 http://pan.baidu.com/s/1skFeGVj ...

最新文章

  1. 【转载】 Python动态生成变量
  2. (转)ZXing生成二维码和带logo的二维码,模仿微信生成二维码效果
  3. Pycharm 导入 Python 包、模块
  4. argument type mismatch怎么解决_怎么做好GMAT 的CR?
  5. mysql一对多查询合并多的一方的数据。
  6. 微软向学生征集Windows 8发行版建议
  7. 建站系统创业项目综合测评:ePower、云优CMS、微加互联、微企点
  8. 如何延缓衰老?十大抗衰小妙招!
  9. 华为交换机重制_华为交换机恢复出厂设置的三种方法
  10. 山东大赛潍坊赛场圆满落幕,优质方案推动智慧城市建设
  11. 【微信小程序教程】点击按钮修改view标签背景颜色
  12. 从晶体管开始聊聊计算机为什么采用二进制
  13. 有限元剖网格之Gmsh安装与使用入门
  14. 为触屏手机而设计系列1—拇指操作的热区死角与控件尺寸
  15. SSD配置和训练以及遇到的坑
  16. 超宽带(UWB)无线通信技术介绍
  17. 应用程序配置文件(.config)
  18. 华为eNSP配置PPPoE认证
  19. matlab车牌匹配时读取,基于Matlab的车牌识别(完整版)详解.doc
  20. 中国代工企业进入汽车行业是为了摆脱苹果?恐怕是更好为苹果服务

热门文章

  1. 深入理解Nacos源码注册中心之服务发现(订阅拉取)
  2. 关于WordPress登录后跳转到指定页面
  3. jQuery基础知识--Form基础(续)
  4. laravel 社会化(联合)登录扩展包(QQ、微信、微博等)
  5. X明X源面试题《三》
  6. 从Android发展看Meego
  7. 《虚拟化与云计算》作者介绍
  8. Java继承的基本概念及其限制(基础语法二)
  9. 机器学习:使用梯度下降实现逻辑回归求解多元分类问题的原理
  10. git学习笔记(2-git初始化配置)