Sqlite3
线程类型:
1.单线程
设置方法:
通过在实例化sqlite3 *db时调用
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
不支持并发操作
2.多线程(默认)
设置方法:
通过在实例化sqlite3 *db时调用
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
不支持并发操作
3.串行(常用)
设置方法:
通过在实例化sqlite3 *db时调用
sqlite3_config(SQLITE_CONFIG_SERIALIZED);
支持并发操作,实际上是系统给对应的地方加锁,变相把并行变为串行访问
sqlite3 *db
数据库句柄,跟文件句柄FILE很类似
int sqlite3_open(const char *filename,sqlite3 **ppDb)
打开数据库,没有数据库时创建。
filename:数据库的文件路径
ppDb:数据库实例
sqlite3_stmt *stmt
这个相当于ODBC的Command对象,用于保存编译好的SQL语句
int sqlite3_prepare_v2(sqlite3 *db,const char *zSql,int nBytes,sqlite3_stmt **ppStmt,const char **pzTail)
创建sqlite3_stmt对象
db:数据库实例
zSql:需要检查的SQL语句
nBytes:SQL语句的最大字节长度
ppStmt:sqlite3_stmt实例,用来获得数据库数据
pzTail:
int sqlite3_exec(sqlite3 *db,const char *sql,int(*callback)(void *,int,char **,char **),void *,char **errmsg)
执行非查询(创表,更新,插入,删除,开启事务,回滚事务,提交事务)的sql语句
db:一个打开的数据库实例
sql:需要执行的SQL语句
callback:SQL语句执行完毕后的回调
void *:回调函数的第一个参数
errmsg:错误信息
sqlite3_bind_xxxx()
绑定sql语句需要用到的参数
第一个参数是sqlite3_stmt *类型
第二个int类型参数-表示参数的在SQL中的序号(从1开始)。
第三个参数为要绑定参数的值。
对于blob和text数值的额外参数:
第四参数是第三个参数数据(Unicode 8or16)的长度,如果是字符串可传入-1代替字符串长度。
第五个参数,类型为void(*)(void*),表示SQLite处理结束后用于清理参数字符串的函数。
没有进行绑定的未知参数将被认为是NULL。
int sqlite3_step(sqlite3_stmt *)
在调用sqlite3_prepare后,使用这个函数在记录集中移动。
可能的返回值:
SQLITE_BUSY: 数据库被锁定,需要等待再次尝试直到成功。
SQLITE_DONE: 成功执行过程(需要再次执行一遍以恢复数据库状态)
SQLITE_ROW: 返回一行结果(使用sqlite3_column_xxx(sqlite3_stmt*,, int iCol)得到每一列的结果。再次调用将返回下一行的结果。
SQLITE_ERROR: 运行错误,过程无法再次调用(错误内容参考sqlite3_errmsg函数返回值)
SQLITE_MISUSE: 错误的使用了本函数(一般是过程没有正确的初始化)
sqlite3_finalize(sqlite3_stmt *pStmt)
清理sqlite3_stmt对象
sqlite3_close(sqlite3 *db)
关闭数据库文件
还有一系列的函数,用于从记录集字段中获取数据,如
sqlite3_column_text()
取text类型的数据。
sqlite3_column_blob()
取blob类型的数据
sqlite3_column_int()
取int类型的数据
其他工具函数
1. 得到结果总共的行数,如果过程没有返回值,如update,将返回0
int sqlite3_column_count(sqlite3_stmt *pStmt);
2. 得到当前行中包含的数据个数,如果sqlite3_step返回SQLITE_ROW,可以得到列数,否则为零。
int sqlite3_data_count(sqlite3_stmt *pStmt);
3. 得到数据行中某个列的数据,在sqlite3_step返回SQLITE_ROW后,使用它得到第iCol列的数据。
sqlite3_column_xxx(sqlite3_stmt*, int iCol);
其中的xxx代表:
blob:指向保存数据内存的指针
bytes, bytes16: 得到该blob类型数据的大小,或者text转换为UTF8/UTF16的字符串长度。
double, int, int64: 数值
text,text16:字符串指针
type:该列的数据类型(SQLITE_INTEGER,SQLITE_FLOAT,SQLITE_TEXT,SQLITE_BLOB,SQLITE_NULL)
注意:如果对该列使用了不同与该列本身类型适合的数据读取方法,得到的数值将是转换过的结果。
4. 得到数据行中某个列的数据的类型
int sqlite3_column_type(sqlite3_stmt*, int iCol);
返回值:
SQLITE_INTEGER,
SQLITE_FLOAT,
SQLITE_TEXT,
SQLITE_BLOB,
SQLITE_NULL
使用的方法和sqlite3_column_xxx()函数类似。
常用sql语句:
建表
create table t_student (id integer, name text, age integer, score real) ;
删表
drop table if exists 表名 ;
插入数据
insert into t_student (name, age) values ('mj', 10) ;//SQL语句中字符串用''单引号
更新数据
update t_student set name = 'jack', age = 20 ;
删除数据
delete from t_student;
条件语句
where 字段 = 某个值 ; // 不能用两个 =
where 字段 is 某个值 ; // is 相当于 =
where 字段 != 某个值 ;
where 字段 is not 某个值 ; // is not 相当于 !=
where 字段 > 某个值 ;
where 字段1 = 某个值 and 字段2 > 某个值 ; // and相当于C语言中的 &&
where 字段1 = 某个值 or 字段2 = 某个值 ; // or 相当于C语言中的 ||
查询数据
select * from t_student where age > 10 ; // 条件查询
模糊查询
select id,name,age from t_person where name like '%%%@%%' order by age asc;"
计算记录的数量
select count (age) from t_student ;
或
select count ( * ) from t_student where score >= 60;
排序
select * from t_student order by age desc ; //降序
或
select * from t_student order by age asc ; // 升序(默认)
或
select * from t_student order by age asc, height desc ;//先按照年龄排序(升序),年龄相等就按照身高排序(降序)
使用limit控制查询结果数量
select * from t_student limit 7;//表示取最前面的7条记录
或
select * from t_student limit 4, 8 ;//跳过最前面4条语句,然后取8条记录
limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据
第1页:limit 0, 5
第2页:limit 5, 5
第3页:limit 10, 5
…
第n页:limit 5*(n-1), 5
简单约束
not null:规定字段值不能为null
unique:规定字段值必须唯一
default:指定字段默认值
create table t_student (id integer, name text not null unique, age integer not null default 1) ;//name字段不能为null,并且唯一;age字段不能为null,并且默认为1
主键约束
用来唯一地标识某一条记录
create table t_student (id integer primary key, name text, age integer) ;//integer类型的id作为t_student表的主键
自增长且做主键
create table t_student (id integer primary key autoincrement, name text, age integer) ;
外键约束
create table t_student (id integer primary key autoincrement, name text, age integer, class_id integer, constraint fk_student_class foreign key (class_id) references t_class (id));
连接表查询
select s.name,s.age from t_student s, t_class c where s.class_id = c.id and c.name = '0316iOS';
使用范例:
打开数据库
sqlite3 *db=NULL;
int result=sqlite3_open([dbPaht UTF8String],&db);
关闭数据库
sqlite3_close(db);
执行不返回数据的SQL语句
char *errorMsg=NULL;
char *sql="create table if not exists myTableName(id integer primary key autoincrement,name text,age integer);";
int result=sqlite3_exec(db,sql,NULL,NULL,&errorMsg);
带占位符插入数据
char *sql="insert into myTableName(name,age)values(?,?);";
sqlite3_stmt *stmt;
if(sqlite3_prepare_v2(db,sql,-1,&stmt,NULL)==SQLITE_OK){//说明SQL语句已经准备成功,没有语法问题
sqlite3_bind_text(stmt,1,"母鸡",-1,NULL);//绑定SQL语句参数
sqlite3_bind_int(stmt,2,28);
}
if(sqlite3_step(stmt)!=SQLITE_DONE){//执行SQL语句,返回SQLITE_DONE代表执行完毕
NSLog(@"插入数据错误");
}
sqlite3_finalize(stmt);//销毁sqlite3_stmt *对象
查询数据
char *sql="select id,name,age from myTableName;";
sqlite3_stmt *stmt;
if(sqlite3_prepare_v2(db,sql,-1,&stmt,NULL)==SQLITE_OK){
while(sqlite3_step(stmt)==SQLITE_ROW){//返回SQLITE_ROW代表遍历到一条新记录
int _id=sqlite3_column_int(stmt,0);//获取每个字段对应的值,第2个参数是字段的索引,从0开始
char *_name=(char *)sqlite3_column_text(stmt,1);
NSString *name=[NSString stringWithUTF8String:_name];
int _age=sqlite3_column_int(stmt,2);
}
}
sqlite3_finalize(stmt);
事务:
@try{
if (sqlite3_exec(dbo, "BEGIN", NULL, NULL, NULL)==SQLITE_OK) {
NSLog(@"启动事务成功");
sqlite3_stmt *stmt;
NSArray *objects=object.insertObject.tableObjects;
for (int i=0; i<objects.count; i++) {
NSString *tableName=[NSString stringWithUTF8String:object_getClassName(object)];
NSString *sqlOffields=@"";
NSString *sqlOfValues=@"";
NSArray *insertSqlObjects=[self arrayOfSqlParameterFieldsName:object];
for (int idx=0; idx<insertSqlObjects.count; idx++) {
NSAssert([insertSqlObjects[idx] isKindOfClass:[OC_Sqlite3_SqlParameterClass class]], @"OC_Sqlite3_TableObjectInterface variable of insertObject must be OC_Sqlite3_TableInsertSqlObject");
OC_Sqlite3_SqlParameterClass *insertSqlObject=(OC_Sqlite3_SqlParameterClass *)insertSqlObjects[idx];
if (idx != insertSqlObjects.count-1) {
sqlOffields=[sqlOffields stringByAppendingFormat:@"%@,",insertSqlObject.fieldName];
sqlOfValues=[sqlOfValues stringByAppendingString:@"?,"];
}else{
sqlOffields=[sqlOffields stringByAppendingFormat:@"%@",insertSqlObject.fieldName];
sqlOfValues=[sqlOfValues stringByAppendingString:@"?"];
}
}
NSString *sql=[NSString stringWithFormat:@"insert into %@ (%@) values (%@)",tableName,sqlOffields,sqlOfValues];
if (sqlite3_prepare_v2(dbo, [sql UTF8String], -1, &stmt, NULL)==SQLITE_OK) {
[self bindSqlParameterInArrayOfSqlParametersClasses:insertSqlObjects stmt:stmt];
if (sqlite3_step(stmt)!=SQLITE_DONE) {
sqlite3_finalize(stmt);
}
}else{
sqlite3_finalize(stmt);
}
}
if (sqlite3_exec(dbo, "COMMIT", NULL, NULL, NULL)==SQLITE_OK) {
NSLog(@"提交事务成功");
sqlite3_finalize(stmt);
return YES;
}
}
}
@catch(NSException *e){
if (sqlite3_exec(dbo, "ROLLBACK", NULL, NULL, NULL)==SQLITE_OK) {
NSLog(@"回滚事务成功");
}
return NO;
}
@finally{}