sqlite

来源:互联网 发布:ipad cellular 知乎 编辑:程序博客网 时间:2024/06/06 09:59

开篇

简介:目前流行的开源嵌入式数据库,具备关系型数据库的基本特征:标准的SQL语法、事务、数据表和索引。


主要特征

1、管理简单,基本无须管理。

2、操作方便,数据库文件可以无缝移植。

3、方便的以多种形式嵌入到其他应用程序中,如:静态库、动态库。

4、易于维护。

综述:灵巧、快速和可靠性。但也舍弃了对RDBMS关键性功能的支持:高并发、细粒度访问控制、丰富的内置函数、存储过程、复杂的SQL语句。



主要优点

1、一致性的文件格式:一致性很强的数据文件+具有很好的事务功能的普通文件+数据访问高效性

2、可以在嵌入式或移动设备上应用:占用资源少+无需管理开销

3、内部数据库;

4、简单的数据分析;

5、产品Demo和测试;



相比RDBMS,sqlite的劣势

1.做不了服务端的数据库

2.数据量很大时处理效率低

3.并发性能很难高效:数据锁粒度很粗,只能提供表级锁,没有提供行级锁。



个性化特征

1、无需配置

2、没有独立的服务器

3、单一磁盘文件:有权限便可随意访问,不用非得在数据库实例进程中

4、平台无关性:备份文件很方便,不用再通过工具到处数据

5、弱类型:除了主键,其它列可以插入任意类型,不用遵循定义时的类型

6、SQL语句编译成虚拟机代码:sqlite自行编译SQL语句,再交由其自带虚拟机来执行




C/C++接口简介


概述:5个API属于核心接口


核心对象:两个:database_connection  prapared_statement

database_connection由sqlite3_open()接口创建并返回。使用其他接口前必须调用改接口获得database_connection对象,调用其他API时需要将该对象作为参数。

prepared_statement:执行SQL相关函数需要该对象作为输入参数


核心接口

1.sqlite3_open:操作sqlite的入口函数,很多sqlite API的句柄参数。返回的database_connection 对象 可以多个线程共享,也可以每个线程独立一个(推荐)。sqlite自带的ATTACH命令可以在一个连接中方便访问多个数据库。

2.sqlite3_prepare:将SQL文本转换为prepared_statement对象,该对象将SQL文本初始化为待执行状态。新的应用程序中可以使用sqlite3_prepare_v2接口替代该函数。

3.sqlite3_step:用于评估sqlite3_prepared函数返回的prepared_statement对象, 如果是查询,则需要循环此函数知道所有数据遍历完,其它操作不需要。

4.sqlite_column:返回当前行指定列的数据 。由一组相关函数来完成该函数的功能,每个函数的返回值类型不同。

sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_column_value
sqlite3_column_count(算总行数)

5.sqlite3_finalize:用于销毁prepared_statement对象。否则会造成内存泄露

6.sqlite3_close:用于关闭之前打开的database_connection对象。


参数绑定:sqlite也支持变量绑定,可以减少SQL语句被动态解析的次数,从而提高数据插查询和数据操作的效率。为此需要使用两个API:sqlite3_reset和sqlite3_bind.




数据表和视图

创建数据表:创建的数据表不能以sqlite_ 开头

1.最简单的数据表:create table testtable(first_col integer);

2.创建带有缺省值的数据表:create table testtable (first_col integer DEFAULT 0,second_col varchar DEFAULT ‘hello’);

3.在指定数据库建表:attach database ‘d/mydb.db’ as mydb;

    create table mydb.testtable (first_col integer);

如果不指定数据库会在main数据库中创建该表,在一个连接中只能有一个main数据库,创建临时表不需指定数据库名

创建临时表:create temp table temptable (first_col integer);

创建普通表: create table testtable (first_col integer);

4.IF NOT EXISTS :避免创建表时会有重复创建的情况,一般情况下创建表时都加这句。

5.create table 。。。 as select 创建所需结果集的副表,例:create table testtable2 as select * from testtable;

.schame命令是sqlite3命令行工具内置命令,用于显示当前数据表的create table 语句。

6.主键约束:

一般主键:create table testtable (first_col integer Primary key asc);

联合主键:create table testtable2 (first_col integer, second_col integer,  PRIMARY KEY(first_col,second_col));

7.唯一性约束:

简单约束:create table testtable (first_col integer UNIQUE);

多约束:create table testtable (first_col integer,second_col integer ,uinique(first_col, second_col) );

NULL 值被视为和其他值都是不同的,这样包括和其他的NULL值:

insert into testtable values(NULL);

8.为空约束:create table testtable (first_col integer NOT NULL);

9.检查性约束:

单行:create table testtable (first_col integer CHECK(first_col < 5));

多行:create table testtable (first_col integer,second_col integer, CHECK(first_col > 0 AND second_col < 0));


修改表

1.修改表名:索引不受影响,视图和触发器会收到影响

ALTER TABLE testtable RENAME TO testtable2;

2.新增字段:

create table testtable(first_col integer);

ALTER TABLE testtable ADD COLUMN second_col integer;


删除表

删除表:DROP TABLE testtable;

删除所有数据: DELETE TABLE testtable;


创建视图

(视图是从一个或多个表导出的表,是一个虚表,所对应的数据不进行实际存储,好处:

1.可以定制用户数据,为特定的用途定义特定的数据;

2.可以简化数据操作:对于频繁发生的动作,建立视图就不用每次都去写很长的SQL语句;

3.使用视图,会使表具有一定的安全性:用户对视图,不可以随意更改或删除,可以保证数据的安全性

4.合并分离的数据,创建分区视图:举例:将不同部门的统计数据合并在同一张表中

)

1.最简单的视图:CREATE VIEW testview AS SELETE * FROM testtable WHERE first_col > 100;

2.创建临时视图:CREATE TEMP VIEW tempView AS SELECT * FROM testtable WHERE first_col > 100;

3."IF NOT EXIST":

CREATE VIEW testview AS SELECT * FROM testtabke WHERE first_col > 100;

CREATE VIEW IF NOT EXIST testview AS SELECT * FROM testtabke WHERE first_col > 100;


删除视图

DROP VIEW testview;

DROP VIEW IF EXISTS testview;


内置函数

聚合函数

avg(x):平均值;不能转换为数字值的string和blog类型直接转为0;结果为浮点型,例外:所有行都为NULL 改函数结果也为NULL;

count(x|*)x字段中值不为NULL的行数,count(*)返回在同一组内的数据行数;

group_concat(x[,y]):连接所有非NULL的x值,y值为连接符,y为空的话链接符默认为@“,”

max(x)求最大值

min(x)求最小值

sum(x)求总和,结果有可能出现上限异常,x都为NULL直接返回0

total(x)功能和sum一样,结果为浮点型,x都为NULL直接返回0,不会跑出异常;


核心函数

abs(x)求绝对值,如果x为NULL,则返回NULL

changes()返回最近执行的操作影响的行数,也可以通过sqlite3_changes()得到相同的结果

coalesce(X,Y,...)返回第一个非NULL的参数,至少有两个参数;

length(X)将X作为字符串返回其长度

lower(X)返回函数参数X的小写形式

ltrim(X[,Y]):删除X左侧所有的Y,若没有Y,则删除左侧所有的空格

rtrim(X[,Y]):删除X右侧所有的Y,若没有Y,则删除右侧所有的空格

Max(X,Y,...)返回参数中最大的值

min(X,Y,...)返回参数中最小的值

nullif(X,Y)相同则返回NULL,不同则返回第一个参数

random()返回一个整型伪随机数

replace(X,Y,Z)X中所有的Y替换成Z,返回替换后的字符串,原字符串不变。

round(X[,Y]):返回数值参数X被四舍五入到Y刻度的值,如果参数Y不存在,缺省参数值为0。 

substr(X,Y[,Z]) 返回函数参数X的子字符串,从第Y位开始(X中的第一个字符位置为1)截取Z长度的字符,如果忽略Z参数,则取第Y个字符后面的所有字符。如果Z的值为负数,则从第Y位开始,向左截取abs(Z)个字符。如果Y值为负数,则从X字符串的尾部开始计数到第abs(Y)的位置开始。 

total_changes()该函数返回自从该连接被打开时起,INSERT、UPDATE和DELETE语句总共影响的行数。我们也可以通过C/C++接口函数sqlite3_total_changes()得到相同的结果。 

trim(x[,y]) 删除X两边所有的Y,若没有Y,则删除两边所有的空格

upper(X) 返回函数参数X的大写形式,缺省情况下,该函数只能应用于ASCII字符。 

typeof(X) 返回函数参数数据类型的字符串表示形式,如"Integer、text、real、null"等。 


日期与时间

date(timestring,modifier,modifer,...):"YYYY-MM-DD" 

time(timestring,modifier,modifier,...):"HH:MM:SS" 

datetime(timestring,modifier,modifier)

strftime(format,timestring,modifier,modifier,...):"YYYY-MM-DD HH:MM:SS" 


1. strftime函数的格式信息:

格式

说明

%d

day of month: 00

%f

fractional seconds: SS.SSS

%H

hour: 00-24

%j

day of year: 001-366

%J

Julian day number

%m

month: 01-12

%M

minute: 00-59

%s

seconds since 1970-01-01

%S

seconds: 00-59

%w

day of week 0-6 with Sunday==0

%W

week of year: 00-53

%Y

year: 0000-9999

%%

%

需要额外指出的是,其余三个时间函数均可用strftime来表示,如:

date(...)time(...)datetime(...)

strftime('%Y-%m-%d', ...)strftime('%H:%M:%S', ...)

strftime('%Y-%m-%d %H:%M:%S', ...)

2. 时间字符串的格式:见如下列表:
1). YYYY-MM-DD
2). YYYY-MM-DD HH:MM
3). YYYY-MM-DD HH:MM:SS
4). YYYY-MM-DD HH:MM:SS.SSS5). HH:MM

6). HH:MM:SS
7). HH:MM:SS.SSS8). now

5)7)中只是包含了时间部分,SQLite将假设日期为2000-01-018)表示当前时间。

3. 修改符:

见如下列表:

1). NNN days

14

SQLite学习手册

2). NNN hours
3). NNN minutes
4). NNN.NNNN seconds5). NNN months
6). NNN years
7). start of month
8). start of year
9). start of day10).weekday N

1)6)将只是简单的加减指定数量的日期或时间值,如果NNN的值为负数,则减,否则加。7)9)则将时间串中的指定日期部分设置到当前月、年或日的开始。10)则将日期前进到下一个星期N,其中星期日为0。注:修改符的顺序极为重要,SQLite将会按照从左到右的顺序依次执行修改符。

4. 示例:--返回当前日期。

sqlite> SELECT date('now');

2012-01-15

--返回当前月的最后一天。
sqlite> SELECT date('now','start of month','1 month','-1 day');2012-01-31
--返回从1970-01-01 00:00:00到当前时间所流经的秒数。
sqlite> SELECT strftime('%s','now');
1326641166
--返回当前年中10月份的第一个星期二是日期。
sqlite> SELECT date('now','start of year','+9 months','weekday 2');2012-10-02 



索引和数据分析

(索引:数据库中一列或多列的值进行排序的一种结构)

创建索引

create TABLE testtable (first_col integer ,second_col integer);

创建简单索引:create index testtable_idx ON testtable(first_col);

创建联合索引:create index testtable_idx2 ON testtable (first_col ASC,second_col DESC);

创建唯一性索引:CREATE UNIQUE INDEX testtable_idx3 ON testtable (second_col DESC);


删除索引:

DROP INDEX testtable_idx;

DROP INDEX IF EXISTS testtable_idx;


重建索引:

重建当前数据库所有索引:REINDEX;

重建某表中的所有索引:REINDEX testtable;

重建当前主数据库中特定索引:REINDEX testtable_idx2;


数据分析:分析数据表和索引中的数据,并将其放于sqlite的内部系统表中,便于查询时选择最优的查询执行路径,从而提高查询效率。

ANALYZE:分析当前连接中所有attached数据库中的表和索引。

ANIALYZE mian:非必须该数据库中的所有表和索引,并生成统计数据

ANALYZE main.testtable 分析特定表或索引 所关联的索引。


数据清理:

 VAVUUM

postgre可以清理具体的表或者索引,splite只能清理主数据库

策略:拷贝一个相同的数据库文件,将没有被删除的数据放在新的数据库文件中。



数据库和事物

attach数据库:将数据库放在缓存中

detach数据库:卸载当前连接中的数据库(main 和 temp 无法卸载)

事物:默认添加隐式事物,保证操作的原子性和一致性


表达式

常用表达式

||
*/%
+-
<< >> & |
< <= > >=
= == != <> IS IS NOT IN LIKEAND
OR
~ NOT 


条件表达式

1. CASE x WHEN w1 THEN r1 WHEN w2 THEN r2 ELSE r3 END
2. CASE WHEN x=w1 THEN r1 WHEN x=w2 THEN r2 ELSE r3 END 


转换表达式

CAST(expr AS target_type) 

target_type: text   /  real  /  integer  /  numberic


数据类型

存储种类和数据类型

NULL:表示该值为NULL值。
INTEGER:无符号整型值。
REAL:浮点值。

TEXT:文本字符串,存储使用的编码方式为UTF-8UTF-16BEUTF-16LE
BLOB:存储Blob数据,该类型数据和输入数据完全相同。 

注:1、布尔类型没有专门的类型,用0/1代替 2、日期也没有专门的类型,text:格式化过的字符串格式,integer:时间戳,real:以julian日期格式存储



类型亲缘性:sqlite会为每一列选择一个亲缘类型,作为存储时的优先选择类型,如否无法转换,则选最优。

具体示例:

声明类型

亲缘类型

应用规则

INT
INTEGER
TINYINT
SMALLINTMEDIUMINTBIGINT
UNSIGNED BIG INTINT2
INT8

INTEGER

1

CHARACTER(20)VARCHAR(255)VARYINGCHARACTER(255)NCHAR(55)
NATIVE CHARACTER(70)NVARCHAR(100)

TEXTCLOB

TEXT

2

BLOB

NONE

3

REAL
DOUBLE
DOUBLE PRECISIONFLOAT

REAL

4

NUMERICDECIMAL(10,5)BOOLEANDATEDATETIME

NUMERIC

5


在线备份

常用备份

常用方法:

1.用sqlite API 或 shell 工具加共享锁

2.使用shell工具拷贝数据库文件到备份目录

3.借出数据库文件上的共享锁

优点:速度快

缺点:

所有该数据库上的链接均被挂起,知道备份结束才被释放

不能拷贝数据库到memory数据库

备份数据库所在主句出现故障时备份数据库可能会倍破坏


备份API

1). 函数sqlite3_backup_init()用于创建sqlite3_backup对象,该对象将作为本次拷贝操作的句柄传给其余两个函数。

2). 函数sqlite3_backup_step()用于数据拷贝,如果该函数的第二个参数为-1,那么整个拷贝过程都将在该函数的一次调用中完成。
3). 函数sqlite3_backup_finish()用于释放sqlite3_backup_init()函数申请的资源,以避免资源泄露。
 

在整个拷贝过程中如果出现任何错误,我们都可以通过调用目的数据库连接的sqlite3_errcode()函数来获取具体的错误码。此外,如果sqlite3_backup_step()调用失败,由于sqlite3_backup_finish()函数并不会修改当前连接的错误码,因此我们可以在调用sqlite3_backup_finish()之后再获取错误码,从而在代码中减少了一次错误处理。 


高级应用技巧

分片拷贝:

1). 函数sqlite3_backup_init()用于创建sqlite3_backup对象,该对象将作为本次拷贝操作的句柄传给其余两个函数。

2). 函数sqlite3_backup_step()被调用用于拷贝数据,和之前方法不同的是,该函数的第二个参数不再是-1,而是一个普通的正整数,表示每次调用将会拷贝的页面数量,如5。
3). 如果在函数sqlite3_backup_step()调用结束后,仍然有更多的页面需要被拷贝,那么我们将主动休眠250ms,然后再重复步骤2).

4). 函数sqlite3_backup_finish()用于释放sqlite3_backup_init()函数申请的资源,以避免资源泄漏


内存数据库

操作时数据库名传”:memory:“,就可调用到内存数据库

临时数据库:数据库名传空字符串,就可调用到临时数据库



临时文件

sqlite运行时有七种临时文件:

1).回滚日志。
2).主数据库日志。
3). SQL语句日志。
4).临时数据库文件。
5).视图和子查询的临时持久化文件。
6).临时索引文件。
7). VACUUM命令使用的临时数据库文件。 


相关编译时参数和指令

1.编译时参数sqlite_temp_store:

范围:0~3

0:临时文件存在磁盘上,不会考虑 temp_store pragma 

1:临时文件存在磁盘上,值会被temp_store pragma 覆盖

2:临时文件存在内存中,值会被temp_store pragma 覆盖

3:临时文件存在内存中,不会被temp_store pragma 覆盖


2.运行时指令temp_store pragma 

范围:0~2

等于0时,临时文件的存储行为完全由SQLITE_TEMP_STORE编译期参数确定。

等于1时,如果编译期参数SQLITE_TEMP_STORE指定使用内存存储临时文件,那么该指令将覆盖这一行为,使用磁盘存储。

等于2时,如果编译期参数SQLITE_TEMP_STORE指定使用磁盘存储临时文件,那么该指令将覆盖这一行为,使用内存存储。 


3.临时文件大小:

大小由以上两个参数决定


4.其它优化策略:

SQLite中由于采用了Page Cache的缓冲优化机制,因此即便临时文件被指定存储在磁盘上,也只有当该文件的大小增长到一定的尺寸后才有可能被SQLite刷新到磁盘文件上,在此之前它们仍将驻留在内存中。 


锁和并发控制

概述:锁和并发控制机制由paper_module模块负责处理;

文件锁:

1.unlocked:缺省态,没有任何锁,可以执行任意读写操作。

2.shared:可读不可写,可由多个进程共同持有共享锁:并发的

3.reserved:同一数据库的同一时刻只能存在一个保留锁和多个共享锁。

4.pending:写操作必须等待共享锁消失(读操作完成)为止。与此同时,新的读操作将不再被允许,防止写锁饥饿现象发生。

5.exclusive:在执行写操作之前,该进程必须先获取该数据库的排它锁,一旦拥有排它锁,就不能有其它的锁。排它锁持有时间会被尽量缩短。


回滚日志:每个数据库都会属于自己的回滚日志


四、数据写入:(还不是很理解

如果某一进程要想在数据库上执行写操作,那么必须先获取共享锁,在共享锁获取之后再获取保留锁。因为保留锁则预示着在将来某一时刻该进程将会执行写操作,所以在同一时刻只有一个进程可以持有一把保留锁,但是其它进程可以继续持有共享锁以完成数据读取的操作。如果要执行写操作的进程不能获取保留锁,那么这将说明另一进程已经获取了保留锁。在此种情况下,写操作将失败,并立即返回SQLITE_BUSY错误。在成功获取保留锁之后,该写进程将创建回滚日志。在对任何数据作出改变之前,写进程会将待修改页中的原有内容先行写入回滚日志文件中,然而,这些数据发生变化的页起初并不会直接写入磁盘文件,而是保留在内存中,这样其它进程就可以继续读取该数据库中的数据了。或者是因为内存中的cache已满,或者是应用程序已经提交了事务,最终,写进程将数据更新到数据库文件中。然而在此之前,写进程必须确保没有其它的进程正在读取数据库,同时回滚日志中的数据确实被物理的写入到磁盘文件中,其步骤如下:

1). 确保所有的回滚日志数据被物理的写入磁盘文件,以便在出现系统崩溃时可以将数据库恢复到一致的状态。
2). 获取PENDING锁,再获取排他锁,如果此时其它的进程仍然持有共享锁,写入线程将不得不被挂起并等待直到那些共享锁消失之后,才能进而得到排他锁。

3). 将内存中持有的修改页写出到原有的磁盘文件中。如果写入到数据库文件的原因是因为cache已满,那么写入进程将不会立刻提交,而是继续对其它页进行修改。但是在接下来的修改被写入到数据库文件之前,回滚日志必须被再一次写到磁盘中。还要注意的是,写入进程获取到的排他锁必须被一直持有,直到所有的改变被提交时为止。这也意味着,从数据第一次被刷新到磁盘文件开始,直到事务被提交之前,其它的进程不能访问该数据库。

当写入进程准备提交时,将遵循以下步骤:
4). 获取排他锁,同时确保所有内存中的变化数据都被写入到磁盘文件中。
5). 将所有数据库文件的变化数据物理的写入到磁盘中。
6). 删除日志文件。如果在删除之前出现系统故障,进程在下一次打开该数据库时仍将基于该HOT日志进行恢复操作。因此只有在成功删除日志文件之后,我们才可以认为该事务成功完成。
7). 从数据库文件中删除所有的排他锁和PENDING锁。一旦PENDING锁被释放,其它的进程就可以开始再次读取数据库了。如果一个事务中包含多个数据库的修改,那么它的提交逻辑将更为复杂,见如下步骤:

34

SQLite学习手册by@_Nicky

4). 确保每个数据库文件都已经持有了排他锁和一个有效的日志文件。
5). 创建主数据库日志文件,同时将每个数据库的回滚日志文件的文件名写入到该主数据库日志文件中。
6). 再将主数据库日志文件的文件名分别写入到每个数据库回滚日志文件的指定位置中。
7). 将所有的数据库变化持久化到数据库磁盘文件中。
8). 删除主日志文件,如果在删除之前出现系统故障,进程在下一次打开该数据库时仍将基于该HOT日志进行恢复操作。因此只有在成功删除主日志文件之后,我们才可以认为该事务成功完成。
9). 删除每个数据库各自的日志文件。
10).从所有数据库中删除掉排他锁和PENDING锁。

最后需要说明的是,在SQLite2中,如果多个进程正在从数据库中读取数据,也就是说该数据库始终都有读操作发生,即在每一时刻该数据库都持有至少一把共享锁,这样将会导致没有任何进程可以执行写操作,因为在数据库持有读锁的时候是无法获取写锁的,我们将这种情形称为"写饥饿"。在SQLite3中,通过使用PENDING锁则有效的避免了"写饥饿"情形的发生。当某一进程持有PENDING锁时,已经存在的读操作可以继续进行,直到其正常结束,但是新的读操作将不会再被SQLite接受,所以在已有的读操作全部结束后,持有PENDING锁的进程就可以被激活并试图进一步获取排他锁以完成数据的修改操作。 


iOS中的sqlite3使用详情:

1.添加开发包libsqlite3.0.dylib

2.代码中的操作:

    //获取数据库文件地址

    NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory,NSUserDomainMask,YES);

    NSString *documentsDirectory = [paths lastObject];

    NSString *path = [documentsDirectory stringByAppendingString:@"database_name"];

    

    //打开数据库文件

    sqlite3 *database;

    sqlite3_open([path UTF8String], &database);

    

    //SQL语句

    sqlite3_stmt *stmt;

    constchar *sql ="SELECT * FROM table_name WHERE pk = ? and name = ?";

    sqlite3_prepare_v2(database, sql, -1, &stmt,NULL);

    

    //绑定参数

    //绑定第一个int参数

    sqlite3_bind_int(stmt,1,1);

    //绑定第二个字符串参数

    sqlite3_bind_text(stmt,2, [@"title"UTF8String], -1,SQLITE_TRANSIENT);

    

    //执行sql

    sqlite3_step(stmt);

    

    //释放sql文资源

    sqlite3_finalize(stmt);

    

    //关闭数据库

    sqlite3_close(database);

    

    /*

     两个重要结构体:

     sqlite3               *pdb, 数据库句柄,跟文件句柄FILE很类似

     sqlite3_stmt      *stmt, 这个相当于ODBCCommand对象,用于保存编译好的SQL语句

     

     五个重要函数

     sqlite3_open(),   打开数据库

     sqlite3_exec(),   执行非查询的sql语句

     sqlite3_prepare(), 准备sql语句,执行select语句或者要使用parameter bind时,用这个函数(封装了sqlite3_exec.

     Sqlite3_step(), 在调用sqlite3_prepare后,使用这个函数在记录集中移动。

     Sqlite3_close(), 关闭数据库文件

     

     从结果集中获取数据

     sqlite3_column_text(), text类型的数据。

     sqlite3_column_blob(),取blob类型的数据

     sqlite3_column_int(), int类型的数据

     PreparedStatement方式处理SQL请求的过程

     */


重要函数说明:

首先建立statement对象:

SQLITE_API int sqlite3_prepare(

  sqlite3 *db,           /* Database handle */

  constchar *zSql,      /* SQL statement, UTF-8 encoded */

  int nByte,             /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt, /* OUT: Statement handle */

  constchar **pzTail    /* OUT: Pointer to unused portion of zSql */

);

SQLITE_API int sqlite3_prepare_v2(

  sqlite3 *db,           /* Database handle */

  constchar *zSql,      /* SQL statement, UTF-8 encoded */

  int nByte,             /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt, /* OUT: Statement handle */

  constchar **pzTail    /* OUT: Pointer to unused portion of zSql */

);

SQLITE_API int sqlite3_prepare16(

  sqlite3 *db,           /* Database handle */

  constvoid *zSql,      /* SQL statement, UTF-16 encoded */

  int nByte,             /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt, /* OUT: Statement handle */

  constvoid **pzTail    /* OUT: Pointer to unused portion of zSql */

);

SQLITE_API int sqlite3_prepare16_v2(

  sqlite3 *db,           /* Database handle */

  constvoid *zSql,      /* SQL statement, UTF-16 encoded */

  int nByte,             /* Maximum length of zSql in bytes. */

  sqlite3_stmt **ppStmt, /* OUT: Statement handle */

  constvoid **pzTail    /* OUT: Pointer to unused portion of zSql */

);


绑定参数:

SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*,int,const void*,int n,void(*)(void*));

SQLITE_API int sqlite3_bind_double(sqlite3_stmt*,int,double);

SQLITE_API int sqlite3_bind_int(sqlite3_stmt*,int,int);

SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*,int,sqlite3_int64);

SQLITE_API int sqlite3_bind_null(sqlite3_stmt*,int);

SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int n,void(*)(void*));

SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*,int,const void*,int,void(*)(void*));

SQLITE_API int sqlite3_bind_value(sqlite3_stmt*,int,const sqlite3_value*);

SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*,int,int n);


执行过程

SQLITE_API int sqlite3_step(sqlite3_stmt*);

可能的返回值

#define SQLITE_OK           0   /* Successful result */

/* beginning-of-error-codes */

#define SQLITE_ERROR        1  /* SQL error or missing database */

#define SQLITE_INTERNAL     2  /* Internal logic error in SQLite */

#define SQLITE_PERM         3   /* Access permission denied */

#define SQLITE_ABORT        4  /* Callback routine requested an abort */

#define SQLITE_BUSY         5  /* The database file is locked */

#define SQLITE_LOCKED       6  /* A table in the database is locked */

#define SQLITE_NOMEM        7   /* A malloc() failed */

#define SQLITE_READONLY     8  /* Attempt to write a readonly database */

#define SQLITE_INTERRUPT    9  /* Operation terminated by sqlite3_interrupt()*/

#define SQLITE_IOERR       10  /* Some kind of disk I/O error occurred */

#define SQLITE_CORRUPT     11  /* The database disk image is malformed */

#define SQLITE_NOTFOUND    12  /* Unknown opcode in sqlite3_file_control() */

#define SQLITE_FULL        13  /* Insertion failed because database is full */

#define SQLITE_CANTOPEN    14  /* Unable to open the database file */

#define SQLITE_PROTOCOL    15  /* Database lock protocol error */

#define SQLITE_EMPTY       16   /* Database is empty */

#define SQLITE_SCHEMA      17  /* The database schema changed */

#define SQLITE_TOOBIG      18  /* String or BLOB exceeds size limit */

#define SQLITE_CONSTRAINT  19  /* Abort due to constraint violation */

#define SQLITE_MISMATCH    20   /* Data type mismatch */

#define SQLITE_MISUSE      21   /* Library used incorrectly */

#define SQLITE_NOLFS       22  /* Uses OS features not supported on host */

#define SQLITE_AUTH        23   /* Authorization denied */

#define SQLITE_FORMAT      24  /* Auxiliary database format error */

#define SQLITE_RANGE       25  /* 2nd parameter to sqlite3_bind out of range */

#define SQLITE_NOTADB      26  /* File opened that is not a database file */

#define SQLITE_ROW         100 /* sqlite3_step() has another row ready */

#define SQLITE_DONE        101 /* sqlite3_step() has finished executing */


工具函数

清理statement对象: SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);

重置过程的执行: SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);

得道结果总共的行数: SQLITE_APIint sqlite3_column_count(sqlite3_stmt *pStmt);

得到当前行中包含的数据个数:SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);

得到数据行中某个列的数据:

SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);

SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*,int iCol);

SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*,int iCol);

SQLITE_API double sqlite3_column_double(sqlite3_stmt*,int iCol);

SQLITE_API int sqlite3_column_int(sqlite3_stmt*,int iCol);

SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*,int iCol);

SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*,int iCol);

SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);

SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*,int iCol);

得到数据行中某个列的数据的类型:SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);



增删改查简单实现

准备工作:获取数据库文件----》打开数据库----》创建数据表

//获取数据文件的路径

    NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory,NSUserDomainMask,YES)lastObject];

    NSString *fileName = [docstringByAppendingPathComponent:@"temp.db"];

    const char *cfileName = [fileNameUTF8String];

    //打开数据库

    int result = sqlite3_open(cfileName, &_db);

    if (result == SQLITE_OK) {

        NSLog(@"数据库成功打开");

        

        constchar  *sql="CREATE TABLE  t_students (id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,age integer NOT NULL);";

        char *errmsg = nil;

        result = sqlite3_exec(self.db, sql,nil,nil, &errmsg);

        if (result == SQLITE_OK) {

            NSLog(@"表创建成功");

        } else {

            NSLog(@"表创建失败");

        }

    } else {

        NSLog(@"打开数据库失败");

    }


//增加数据

- (void)insert

{

    for (int i = 0; i < 20; i++) {

        //拼接SQL语句

        NSString *name = [NSStringstringWithFormat:@"文晓--%d",arc4random_uniform(100)];

        int age = arc4random_uniform(20) +10;

        NSString *sql = [NSStringstringWithFormat:@"INSERT INTO t_students (name,age) VALUES('%@',%d)",name,age];

        

        //执行SQL语句

        char *errmsg = nil;

        sqlite3_exec(self.db, sql.UTF8String,nil,nil, &errmsg);

        if (errmsg) {

            NSLog(@"插入数据失败--%s",errmsg);

        } else {

            NSLog(@"插入数据成功");

        }

    }

}


//查询数据

- (void)select

{

    constchar *sql ="SELECT id , name , age FROM t_student WHERE age<20;";

    sqlite3_stmt *stmt = nil;

    

    //查询前准备工作

    if (sqlite3_prepare_v2(self.db, sql, -1, &stmt,nil) ==SQLITE_OK) {

        NSLog(@"查询语句没有问题");

        

        while (sqlite3_step(stmt) ==SQLITE_OK) {

            int ID = sqlite3_column_int(stmt,0);

            const unsignedchar *name =sqlite3_column_text(stmt,1);

            int age = sqlite3_column_int(stmt,2);

            NSLog(@"%d,%s,%d",ID,name,age);

        }

    } else {

        NSLog(@"查询语句有问题");

    }

}






0 0