目录正文效果图什么是数据库iOS中的数据存储方式什么是sqliteSQL语句的种类数据定义语句(DDL:Data Definition Language)数据操作语句(DML:Dat
本文重点说下常用的本地数据库操作,Sqlite和封装的FMDB的使用,以及Model的存与取。
调试软件使用的是Navicat,支持大部分主流数据库(包括SQLite)
SQLite将数据划分为以下几种存储类型:
create table t_student(name, age);
为了保持良好的编程规范、方便程序员之间的交流,编写建表语句的时候最好加上每个字段的具体类型示例:create table t_student (id integer, name text, age inetger, score real) ;
良好的数据库编程规范应该要保证每条记录的唯一性,为此,增加了主键约束,也就是说,每张表都必须有一个主键,用来标识记录的唯一性,在创表的时候用primary key声明一个主键:
示例:create table t_student (id integer primary key, name text, age integer) ;
主键的设计原则:
integer类型的id作为t_student表的主键。
如果想要让主键自动增长(必须是integer类型),应该增加autoincrement,
示例:create table t_student (id integer primary key autoincrement, name text, age integer) ;
注意:这个删是将整个表删除
示例:drop table if exists t_student ;
示例:insert into t_student (name, age) values (‘小虎牙’, 10) ;
数据库中的字符串内容应该用单引号 ‘ ’ 括住
示例:delete from t_student ;
注意:上面的示例会将t_student表中所有记录都删掉
示例:
update t_student set name = ‘rc', age = 18 ;
注意:上面的示例会将t_student表中所有记录的name都改为rc,age都改为18
示例 : select name, age from t_student ;select * from t_student ;
如果只想更新或者删除某些固定的记录,那就必须在DML语句后加上一些条件 条件语句的常见格式
示例:
update t_student set age = 5 where age > 10 and name != ‘rc’ ;
delete from t_student where age <= 10 or age > 30 ;
update t_student set score = age where name = ‘rc’ ;
格式:
示例:
select name myname, age myage from t_student ;
select s.name, s.age from t_student s ;
select count (age) from t_student ;
select count ( * ) from t_student where score >= 60;
按照某个字段的值,进行排序搜索 select * from t_student order by 字段 ; 示例:select * from t_student order by age ;
默认是按照升序排序(由小到大),也可以变为降序(由大到小) 降序 :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可以精确地控制查询结果的数量,比如每次只查询10条数据
select * from t_student limit 4, 8 ;
limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据
第1页:limit 0, 5 第2页:limit 5, 5 第3页:limit 10, 5 ... 第n页:limit 5*(n-1), 5
建表时可以给特定的字段设置一些约束条件,常见的约束有
建议:尽量给字段设定严格的约束,以保证数据的规范性
name字段不能为null,并且唯一 age字段不能为null,并且默认为1
示例:create table t_student (id integer, name text not null unique, age integer not null default 1) ;
优点:
FMDB
FMDB有三个主要的类
通过指定SQLite数据库文件路径来创建FMDatabase对象
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"数据库打开失败!");
}
文件路径有三种情况
在FMDB中,除查询以外的所有操作,都称为“更新”,create、drop、insert、update、delete等 使用executeUpdate:方法执行更新
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFORMat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
示例 :[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @18, @"rc"]
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
// 查询数据
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
// 遍历结果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
}
FMDatabase这个类是线程不安全的,如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱等问题 为了保证线程安全,FMDB提供方便快捷的FMDatabaseQueue类
// FMDatabaseQueue的创建
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
...
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"rc"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
事务、回滚 : 操作数据库时,会出现这种情况:更新10条记录,当更新到第5条时,服务器宕机了,后面的麻烦就来了,我们要每次判断哪条记录更新了,哪条记录没更新!这时候就用到了事务,将更新10条记录放到一个事务中,成功完成所有更新操作时再提交,只要其中一条记录更新失败就回滚,回到初始状态,简单的说就是要么全部成功,要么全部不成功!
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"rc"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
//事务回滚
*rollback = YES;
以头条新闻为例,一条新闻为一条记录:
1.先在本地数据库查找是否存在缓存,存在则显示缓存的新闻,
2.不存在则去头条服务器请求数据显示,同时缓存
思路很简单: 要做到请求了今日头条的新闻缓存到本地数据库后,下次打开直接在数据库取出数据后显示。
两种情况:
1、直接缓存后天返回的JSON数据 ,好处是简单,避免了模型转字典的过程,数据原始,但是如果对数据有更新,比如:新闻是否已读等。
2、将服务器返回的json转成model(模型)再缓存,缺点就是可能在模型中有为了方便开发而新增的字段,而这些字段是不需要进行缓存的。
第1种比较简单,就以第2种为例: 写了一个新闻缓存的工具类
NewsCacheTool.h
+ (void)saveNewsToDatabase:(NSArray *)newsArray;
+ (NSArray *)selectNewsToDatabase:(NSString *)userID;
+ (void)clearNewsCache:(void(^)(BOOL success))flag;
NewsCacheTool.m
static FMDatabase *_db;
// 第一次使用就开始创建表
+ (void)initialize{
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [cachePath stringByAppendingPathComponent:@"News.sqlite"];
_db = [FMDatabase databaseWithPath:filePath];
if ([_db open]) {
NSLog(@"打开数据库成功");
// 自增主键、userID、二进制数据流
NSString *sql = @"create table if not exists t_news (id integer primary key autoincrement,userID text,dict blob);";
BOOL success = [_db executeUpdate:sql];
if (success) {
NSLog(@"创建表成功");
}else{
NSLog(@"创建表失败");
}
}else{
NSLog(@"打开数据库失败");
}
}
// 缓存数据,这里为了安全起见应该使用事务
+ (void)saveNewsToDatabase:(NSArray *)newsArray{
// 遍历模型数组
for (NewsModel *nesw in newsArray){
// 用户的id应该从自己的服务器取得
NSString *userID = @"001";
// 这是模型转字典的,自己用runtime简单实现了,有很多优秀的第三方库可以使用,自选
NSDictionary * newsDic = [nesw getDictionayFromModel];
NSError *error;
NSData *data;
if (@available(iOS 11.0, *)){
data = [NSKeyedArchiver archivedDataWithRootObject:newsDic requiringSecureCoding:YES error:&error];
}else{
data = [NSKeyedArchiver archivedDataWithRootObject:newsDic];
}
if (data == nil || error) {
NSLog(@"缓存失败:%@", error);
return;
}
BOOL success = [_db executeUpdate:@"insert into t_news (userID,dict) values(?,?)",userID,data];
if (success) {
NSLog(@"插入成功");
}else{
NSLog(@"插入失败");
}
}
}
// 在数据库中读取数据
+ (NSArray *)selectNewsToDatabase:(NSString *)userID{
NSString *sql = [NSString stringWithFormat:@"select * from t_news where userID = '%@';",userID];
FMResultSet *set = [_db executeQuery:sql];
NSMutableArray *array = [NSMutableArray array];
while ([set next]) {
NSData *data = [set dataForColumn:@"dict"];
NSError *error;
NSDictionary *dic;
if (@available(iOS 11.0, *)) {
dic = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:data error:&error];
} else {
dic = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
if(dic){
NewsModel *news = [[NewsModel alloc]initWithDictionary:dic];
[array addObject:news];
}
}
return array;
}
// 清除新闻缓存
+ (void)clearNewsCache:(void (^)(BOOL success))flag{
BOOL success = [_db executeUpdate:@"delete from t_news;"];
if(flag){
flag(success);
}
}
模型转字典的过程中,在NewsModel类中,用runtime简单实现了,实际开发中可能会多层嵌套字典或数据,市面上有很多成熟优秀的轮子,可自行选择。
SqliteDemo
以上就是iOS中Sqlite和FMDB使用详解的详细内容,更多关于iOS Sqlite FMDB 使用的资料请关注编程网其它相关文章!
--结束END--
本文标题: iOS中Sqlite和FMDB使用详解
本文链接: https://lsjlt.com/news/169751.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0