股票场内基金交易,没时间盯盘?
之前我已经通过《以文件形式存储数据的几种方式》和《CoreData 使用入门》分别介绍了一些不同重量级的数据持久化方式。当时虽然也学习了 FMDB,但是由于知识储备不够,对于某些概念不是很理解,所以放了一阵。最近补上了多线程的知识,,又在一些实例应用中用上了 FMDB 加强了理解,终于可以把这坑填一填了。
CoreData 虽然使用起来更加面向对象,但是繁复的内部处理对于性能的消耗也是不容忽视的,有时会显得过于“重量级”,因此直接操作数据库成为了不错的解决方案。不过苹果原生的 SQLite API 在理解和使用上相当不友好,于是催生出了许多对其进行封装的框架,FMDB 就是其中的佼佼者。
SQL 语句
很可惜,不像 CoreData 那样对数据库内部操作也进行了封装,可以直接通过对象处理数据,FMDB 仍需要通过编写 SQL 语句来操控数据库。
字段类型
SQLite 将数据分为以下几种类型:
1 2 3 4 5 |
integer : 整数(主键必须设置成 integer) real : 实数(浮点数) text : 文本字符串 blob : 二进制数据 |
实际上 SQLite 是无类型的。无论创表时指定的字段类型是什么,存储是依然可以存储任意类型的数据,而且在创表时也可以不指定字段类型。不过为了良好的编程规范和方便开发人员交流,使用时最好设置正确的字段类型。
种类
SQL 语句主要分为以下几种:
数据定义语句(DDL: Data Definition Language)
包括 create、drop 等操作,在数据库中新建和删除表;
1 2 3 4 5 |
/* 删表 */ DROP TABLE IF EXISTS t_person; /* 建表 */ CREATE TABLE IF NOT EXISTS t_person (id integer PRIMARY KEY, name text, age integer, height real); |
数据操作语句(DML:Data Manipulation Language)
包括 insert、delete、 update 等操作,对应于常见概念中的“增、删、改”,分别对表中的数据进行添加、删除和修改;
1 2 3 4 5 6 7 |
/* insert 添加操作 */ INSERT INTO t_person (id, name, age, height) VALUES (1, 'Sam', 11, 1.11); /* update 修改操作 */ UPDATE t_person SET name = 'Tom', age = 20; /* 该操作修改的是该字段的全部数据 */ /* delete 删除操作 */ DELETE FROM t_person /* 删除 t_person 下全部数据 */ |
条件关键字
包括 where、order by、limit、having 等,用于给 DML 语句和下面介绍的 DQL 语句增加条件限制;
数据查询语句(DQL: Data Query Language)
关键字select,用于查询获得表中的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* select查询操作 */ SELECT name, age FROM t_person; SELECT * FROM t_person WHERE age > 20 and age < 50; /* *号表示查询所有字段 */ SELECT COUNT(*) FROM t_person WHERE age > 60; /*利用 COUNT(*)函数查询数量 */ SELECT * FROM t_person ORDER BY age ASC, height DESC; /* 排序,先按年龄升序排列,相同时按成绩降序排列 */ SELECT * FROM t_person WHERE height > 1.70 LIMIT 5, 10; /* 跳过前面 5 条数据,取后面10条数据 */ SELECT * FROM t_person WHERE height > 1.70 LIMIT 10; /* 读取前 10 条数据 */ SELECT * FROM t_person WHERE height LIKE '%5%'; /* 模糊查询。查询所有包含 "5" 的 height 字段数据 */ SELECT * FROM t_person WHERE height LIKE '5%'; /* 查询所有以 "5" 开头的 height 字段数据 */ |
约束
简单约束
建表时给需要的字段设置,常见的有 not null、unique、default;
1 2 |
CREATE TABLE IF NOT EXIST t_student (id integer, name text NOT NULL UNIQUE, age integer NOT NULL DEFAULT 20); |
主键约束
建表时用 primary key 声明的字段,保证每条记录的唯一性;
1 2 |
CREATE TABLE IF NOT EXIST t_student (id integer PRIMARY KEY, name text); |
-
必须是integer类型;
-
默认包含NOT NULL、UNIQUE 和 AUTOINCREMENT(自动增长)三个约束。
外键约束
建立表与表之间的联系。
1 2 3 4 5 |
/* 先新建一个 class 表 */ CREATE TABLE IF NOT EXISTS t_class (id integer PRIMARY KEY, name text); /* 新建 student 表,给 class_id 创建外键约束 */ CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY, name text, age integer, class_id integer, CONSTRAINT fk_t_student_class_id_t_class_id FOREIGN KEY(class_id) REFERENCES t_class(id)); |
FMDB
使用前需要先在项目主文件 -> Build Phases -> Link Binary With Libraries 中导入 SQLite 库(libsqlite3.tbd 和 libsqlite3.0.tbd 皆可)。
FMDB 常用的三个类:
-
FMDatabase:一个 FMDatabase 对象就时一个单独的 SQLite 数据库,用来执行 sql 语句;
-
FMResultSet:FMDatabase 执行查询后的结果集;
-
FMDatabaseQueue:保证在多线程中执行多个操作的线程安全。
FMDatabase
创建并打开数据库
1 2 3 4 5 6 7 8 9 |
// 创建数据库实例对象 FMDatabase *db = [FMDatabase databaseWithPath:filePath]; // 打开数据库 if ([self.db open]) { NSLog(@"打开成功"); } else { NSLog(@"打开失败"); } |
其中 filePath 一般是文件路径,也可以是空字符串或直接为空(不推荐)。
executeUpdate
FMDB 中除查询外的全部操作都称之为更新,采用executeUpdate:方法。
1 2 3 4 5 6 |
// 创表 [db executeUpdate:@"create table if not exists t_person (id integer primary key, name text not null, age integer, height real);"] // insert操作(常用的 2 种格式) [db executeUpdate:@"insert into t_person (name, age, height) values(?, ?, ?);",name, age, height]; [db executeUpdateWithFormat:@"insert into t_person (name, age, height) values(%@, %d, %f);\n",name, age, height]; // 添加字符串不用添加单引号 |
这里有个注意点是 executeUpdate: 方法由于直接封装了 SQLite API 相关函数因此在带参数的输入格式上语 OC 有所不同,如果觉得不方便建议使用 executeUpdateWithFormat: 方法。
FMResultSet、executeQuery
FMDB中查询采用 executeQuery: 方法,查询结果为 FMResultSet 对象。
1 2 3 4 5 6 7 8 9 10 |
// 获得结果集 FMResultSet *rs = [self.db executeQuery:@"select * from t_person where age > 20 order by asc limit 10;"]; // 升序排列 age 字段数据大于 20 的前 10 个数据 // 遍历结果集,取得查询数据 while (rs.next) { NSString *name = [rs stringForColumn:@"name"]; NSInteger age = [rs intForColumn:@"age"]; CGFloat height = [rs doubleForColumn:@"height"]; NSLog(@"%@, %d, %f",name, age, height); } |
FMDatabaseQueue
在多线程中同时使用一个 FMDatabase 实例是存在安全隐患的,为此 FMDB 提供了 FMDatabaseQueue 类。它内部声明了一个串行队列,同时给其设置了一个标识(specific)避免出现死锁,我们通过 FMDatabaseQueue 相关方法输入的数据库代码都会放进这个队列中同步执行,以保证线程安全。
初始化方法,默认已开启数据库:
1 2 |
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:filePath]; |
使用方法,在 block 中获得 FMDatabase 对象进行设置:
1 2 3 4 5 6 7 |
- (void)inDatabase:(void (^)(FMDatabase *db))block; - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; // 事物(transaction) - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; // 延迟事物(deferredTransaction) - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; // 保存点(savePoint) |
想获得去掉 5 元限制的证券账户吗?

如果您想去掉最低交易佣金 5 元限制,使用微信扫描左边小程序二维码,访问微信小程序「优财助手」,点击底部菜单「福利」,阅读文章「通过优财开证券账户无最低交易佣金 5 元限制」,按照文章步骤操作即可获得免 5 元证券账户,股票基金交易手续费率万 2.5。
请注意,一定要按照文章描述严格操作,如错误开户是无法获得免 5 元证券账户的。