基于FMDB的数据库基本操作

我们都知道, 不管使用任何一种高级编程语言, 都会遇到需要做本地缓存的情况. 当然, 本地缓存方式可能有多种方式. 但如果需要对本地缓存做灵活的操作, 基于sql 的数据库依然是首选. 本文将从基础的sql语句出发, 衍申到 iOS 开发中对数据库的应用.

一. SQL基础

SQL(结构化查询语言)给我们提供了数据库的创表,删表,数据的增删改查等基本操作. 接下来将依次举例演示这些操作.

  • 创表
    判断如果不存在 StudentTable 则创建. 将 id 设为主键, 以分号结尾.
    create table if not exists StudentTable (id integer primary key, name text not null, score integer not null);
    如果主键不需要外界输入, 而是通过默认的累加方式, 可以将主键设为自增模式.
    create table if not exists StudentTable (id integer primary key autoincrement, name text not null, score integer not null);
    主键有默认的唯一性, 如果需要将除主键意外的其他字段设置唯一性属性, 需要用unique 来修饰该字段.
    create table if not exists StudentTable (id integer primary key autoincrement, name text unique not null, score integer not null);

  • 删表
    删除数据库表StudentTable
    delete from StudentTable;


  • insert into StudentTable(id,name,score) values ('1','小明','99');

  • delete from StudentTable where id='1' and name='小明';

  • 修改Student表中 id = 1 的这条数据, 同时修改两个字段. 修改name = '大明', 修改score='90' . 同时修改多个字段值时, 中间用逗号隔开.
    update StudentTable set name='大明',score='90' where id='1';

  • 查询 id = 1 的这条数据的所有字段值.
    select * from StudentTable where id='1';
    查询id = 1 的这条数据对应的name 的字段值.
    select name from StudentTable where id = '1';
    查询score = 90 的这条数据的name 的字段值, 并按照id 的升序排列. (如果需要降序排列, 将asc 替换成 desc 即可)
    select name from StudentTable where score = '90' order by id asc;

二. FMDB中SQL的使用

FMDB 是在iOS开发中常用的第三方数据库操作框架, 其底层实现是对sqlite 的封装. 下文中用到的self.dataBase 是FMDatabase 的单例.

1. FMDatabase 调用 sql 不需要返回数据

FMDatabase 在调用sql 时, 不需要返回数据的情况有 增, 删, 改. 在这种情况下, FMDatabase 提供了两种调用方式.

  • 通过 executeUpdate直接调用组装好的sql, 不需要传入参数. (以增加一条记录为例)
  NSString *sqlString = [NSString stringWithFormat:@"insert into StudentTable(id,name,score) values ('%@','%@','%@');", @1, @"小明", @99];
       
 BOOL result = [self.dataBase executeUpdate:sqlString];
  • 通过 executeUpdateWithFormat 调用sql. FMDataBase自带有格式化输入占位符 '?' ;
BOOL result = [self.dataBase executeUpdateWithFormat:@"insert into StudentTable(id,name,score) values (?,?,?)", @1, @"小明", @99];

2. FMDatabase 调用 sql 语句需要返回数据

FMDatabase 在调用sql 时,需要返回数据的操作是 查询. 查询操作也有以上两种调用方式

  • 通过 executeQuery直接调用组装好的sql, 不需要传入参数;
  • 通过 executeQueryWithFormat 调用sql. FMDataBase自带有格式化输入占位符 '?' ;

查询操作返回数据类型是FMResultSet, 需要对这个类型的数据进行解析, 转成模型数据.

- (NSArray *)selectStudentByID:(NSNumber *)ID {
    
    NSMutableArray *resultArray = [NSMutableArray array];
    
    FMResultSet *set = [self.dataBase executeQueryWithFormat:@"select * from StudentTable where id = ?;", ID];
    while (set.next) {
        
        Student *stu = [[Student alloc] init];
        stu.ID = [set objectForColumnName:@"id"];
        stu.name = [set objectForColumnName:@"name"];
        stu.score = [set objectForColumnName:@"score"];
        [resultArray addObject:key];
    }
    return resultArray;
}

三. 异步线程的FMDB

在项目中曾经遇到这么一种情况, 快速切换页面, 大量网络数据需要更新本地数据库的缓存. 操作的特点是: 数据量大, 对数据库的操作频繁, 更有甚者,多个网络数据流同时操作了同一张数据表. 那么这样的操作必然不能放到主线程中执行, 整个app 会卡顿的无法使用, 用户体验相当不好.

这时, 我考虑使用异步线程, 将这些耗时操作放到子线程中去执行. 事实上我也这么尝试了, app 卡顿的现象真的解决了. 在测试过程中, 新的问题又出现了. 问题就是: 多个动作同时操作数据库时, 未必所有动作都会被执行. 因为某张数据表正在被操作, 其他动作则无法操作而被跳过了. 这样, 每次从本地缓存中读取的数据就会和预期的有较大出入.

要解决以上问题, FMDB为我们提供了基于 NSOperationQueue 的多线程操作. 将所有操作放入队列中, iOS系统会自动分配子线程, 确保每个动作都会被执行, 不会因为数据库正在被操作而丢弃其他操作.
下文中用到的self.dataBaseQueue 是FMDatabaseQueue的单例.

- (void)insertStudentsArray:(NSArray *)studentsArray {
    
    [self.dataBaseQueue inDatabase:^(FMDatabase *db) {
        for (Student *stu in studentsArray) {
            [self insertStu: stu];
        }
    }];
}

注意: FMDB提供的队列操作是不能嵌套的, 不能队列中再调用同一队列. 在上面的例子中, -(void)insertStu:(Student*)stu; 这个方法内部就不能再调用[self.dataBaseQueue inDatabase:^(FMDatabase *db) { }]; 这个方法了, 否则程序会崩溃.

你可能感兴趣的:(基于FMDB的数据库基本操作)