FMDB与数据存储的学习
文章目录
前言
这周开始挑选完项目,我们就要进入项目内容的相关学习,为后面项目的编写做铺垫,本篇文章就是介绍了数据存储的相关知识。
SQLite
SQLite,是一款轻型的数据库,它包含在一个相对小的C库中。
设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
支持Windows/Linux/Unix等等主流PC操作系统和Android/iOS等主流手机操作系统
SQLite数据类型
SQLite一共只有五种数据类型
- NULL:表示该值为NULL值。
- INTEGER:整型值。
- REAL:浮点值。
- TEXT: 文本字符串,存储使用的编码方式为UTF-8、UTF-16。
- BLOB:二进制大对象(BLOB)是任意类型的数据。
SQLite常用函数
- sqlite3_open------打开数据库,如果目录下没有就创建一个
- sqlite3_close------关闭数据库
- sqlite3_exec ------ 用于执行 SQL 语句
- sqlite3_prepare_v2------用于将 SQL 查询语句编译为可执行的 SQLite 语句。
- sqlite3_step
- sqlite3_column_text
SQLite相关语句的使用
界面配置
想要在OC之中使用SQLite,需要以下步骤:
在项目的general选项之中,找到Frameworks, Libraries, and Embedded Content的选项
点击加号,然后在弹出的搜索栏之中寻找sqlite
这样子就可以将框架导入到我们的工程文件了
学习SQLite之前还需要了解部分关于NSBundle的相关内容,有兴趣的读者可以进行了解
SQLite的OC使用
创建Model
我们创建一个person来进行文件操作
objc
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *phone;
@property (strong, nonatomic) NSString *address;
-(instancetype)initWithName:(NSString *)name andPhone:(NSString *)phone andAddress:(NSString *)address;
@end
#import "Person.h"
@implementation Person
-(instancetype)initWithName:(NSString *)name andPhone:(NSString *)phone andAddress:(NSString *)address {
if(self = [super init]) {
self.name = name;
self.phone = phone;
self.address = address;
}
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"Name:%@,Phone:%@,Address:%@", _name,_phone,_address];
}
@end
创建库
objc
-(void)createDB: (NSString *)dbName{
//1.查找沙盒
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//2.拼接数据库
NSString *dbPath = [docPath stringByAppendingPathComponent:dbName];
//3.常见数据库
int result = sqlite3_open([dbPath UTF8String], &sqlite);
if (result == SQLITE_OK) {
NSLog(@"数据库创建成功");
}
else {
NSLog(@"数据库创建失败");
}
}
创建表格
objc
-(void) createTab: (NSString *)tabName{
NSString *sql = [NSString stringWithFormat:@"create table %@(id integer primary key autoincrement, name text, phone text, address text)", tabName];
char *error;
int result = sqlite3_exec(sqlite, [sql UTF8String], NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"表格创建成功");
} else {
NSLog(@"表格创建失败");
}
}
其中sql
之中的内容如下
id integer primary key autoincrement
:
id
:列名,表示每一行的唯一标识符。integer
:数据类型,表示id
列的数据类型是整数。primary key
:指定id
列是主键,主键是每行数据的唯一标识,不允许重复。autoincrement
:表示id
值会自动递增,每次插入新数据时,id
会自动加 1,从而确保每一行有一个唯一的id
值。
剩下的name
,address
等内容其实就是对应的每列内容所存储的方式
objc
int sqlite3_exec(
sqlite3 *db, /* 数据库连接对象 */
const char *sql, /* 要执行的 SQL 语句 */
int (*callback)(void*,int,char**,char**), /* 回调函数 */
void *data, /* 回调函数的用户数据 */
char **errmsg /* 错误信息 */
);
值得注意的是,在创建表格之前我们需要先打开数据库才可以成功创建表格
添加数据
objc
-(void)insertPerson: (Person *)person{
NSString *sql = [NSString stringWithFormat:@"insert into stus(name, phone, address) values('%@', '%@', '%@')", person.name, person.phone, person.address];
char *error;
int result = sqlite3_exec(sqlite, [sql UTF8String], NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"数据插入成功");
} else {
NSLog(@"数据插入失败:%s",error);
}
}
用终端查看表中数据
对于插入表中的数据,我们可以使用终端来进行查看,首先是找到Document目录下的路径,我们可以打印出来
objc
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"%@",docPath);
拿到Document的路径之后,就在终端使用cd进入目录,然后直接使用以下命令进入DB文件
objc
sqlite3 your_database_file.db//这里换成你自己的库名
查看所有表
在 SQLite 命令行模式中,输入以下命令列出所有表:
sqlite
.tables
查看表结构
如果想查看某个表的结构(例如 table_name
表),可以使用以下命令:
sqlite
.schema table_name
查看表内容
要查看表中的数据,可以使用 SELECT
语句,例如:
sqlite
SELECT * FROM table_name;
退出 SQLite
完成后,输入 .exit
或按 Ctrl + D
退出 SQLite 命令行模式:
sqlite
.exit
删除数据
objc
-(void)deletePerson: (NSString *)personName {
NSString *sql = [NSString stringWithFormat:@"delete from stus where name = '%@'", personName];
char *error;
int result = sqlite3_exec(sqlite, [sql UTF8String], NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"删除数据成功");
}
else {
NSLog(@"删除数据失败:%s",error);
}
}
这个删除功能只是在库之中无法查询到删除之后的数据,但是在库中仍然存在,所以这是一个相对不太安全的操作,需要我们在实际运用的时候进行注意
更新数据
objc
-(void)updatePerson: (Person *)person{
NSString *sql = [NSString stringWithFormat :@"update stus set phone ='%@', address = '%@' where name = '%@'", person.phone, person.address, person.name];
char *error;
int result = sqlite3_exec(sqlite, [sql UTF8String], NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"更新数据成功");
}
else {
NSLog(@"更新数据失败:%s",error);
}
sqlite3_close(sqlite);
}
这个程序是根据学生名字来进行更新相关信息
查询数据
objc
(NSArray<Person *> *)queryPersonByName: (NSString *)name{
NSString *sql = [NSString stringWithFormat:@"SELECT phone, address FROM stus WHERE name = '%@'", name];
sqlite3_stmt *stmt;
int result = sqlite3_prepare_v2(sqlite, [sql UTF8String], -1, &stmt, NULL);
NSMutableArray *person = [NSMutableArray array];
if (result == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char *Phone = (const char *) sqlite3_column_text(stmt, 0);
const char *cAddress = (const char *)sqlite3_column_text(stmt, 1);
Person *p = [[Person alloc] initWithName:name andPhone:[NSString stringWithUTF8String:Phone] andAddress:[NSString stringWithUTF8String:cAddress]];
[person addObject:p];
}
} else {
NSLog(@"查询失败: %s", sqlite3_errmsg(sqlite));
}
return person;
}
sqlite3_stmt *stmt;
声明了一个 sqlite3_stmt
结构体指针 stmt
,相当于行指针,用于存储编译后的 SQL 语句。
sqlite3_prepare_v2
函数编译 SQL 语句,将编译结果放入 stmt
,以供后续执行。
result
会接收 sqlite3_prepare_v2
的返回值,若 result
等于 SQLITE_OK
,则表示 SQL 语句准备成功。
sqlite3_step
:逐行获取查询结果。如果 sqlite3_step
返回 SQLITE_ROW
,说明查询到了数据。
sqlite3_column_text
:用于获取当前行的指定列值。sqlite3_column_text(stmt, 0)
获取第一列 (phone
) 的值,sqlite3_column_text(stmt, 1)
获取第二列 (address
) 的值。
FMDB
了解完相关的SQLite3的原理,我们可以也使用第三方库FMDB来进行来进行数据库存储
FMDB是iOS 和 macOS 平台上一个用于操作 SQLite 数据库的库,它封装了 SQLite 的 C 语言 API,使得在 Objective-C 中处理数据库操作更加简便和安全。
新建类
我们新建一个Model
objc
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Student : NSObject
@property (strong, nonatomic) NSString *name;
@property (assign, nonatomic) int age;
@property (strong, nonatomic) NSString *sex;
-(instancetype)initWithName:(NSString *)name andAge:(int)age andSex:(NSString *)sex;
@end
NS_ASSUME_NONNULL_END
建立FMDB数据库
objc
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *sqlFilePath = [path stringByAppendingPathComponent:@"stu.db"];
self.db = [FMDatabase databaseWithPath:sqlFilePath];
我们用拼接的方法,首先获取沙盒文件之中Document路径
然后我们就用以下方式用路径来创建数据库
一个文件的系统路径
:如果不存在该路径,会自动创建一个空字符串@""
:在一个临时目录下创建一个空的数据库,当数据库连接关闭,自动删除数据库文件NULL
:会创建一个内存中临时数据库,当数据库连接关闭的时候,将被自动删除
后面两种不是我们要的因为没有保存数据,那么我们使用第一种方法
objc
FMDatabase *db = [FMDatabase databaseWithPath:sqlFilePath];
self.DataBase = db;
打开数据库
objc
-(void)createDB{
NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES).firstObject;
NSString *fileName = [docPath stringByAppendingPathComponent :@"student.db"];
self.db = [FMDatabase databaseWithPath: fileName];
BOOL isSuccess = [self.db open];
if (isSuccess) {
NSLog(@"打开数据库成功");
}
else {
NSLog(@"打开数据库失败");
}
}
创建表
objc
-(void)createTab {
[self createTab];
NSString *sql = @"create table t_stu(id integer primary key autoincrement, name text, age integer, sex text)";
BOOL isSuccess = [self.db executeUpdate: sql];
if (isSuccess) {
NSLog(@"数据表创建成功");
} else {
NSLog(@"数据表创建失败");
}
[self.db close];
}
添加数据
objc
-(void)insertStu:(Student *)stu{
[self createDB];
NSString *sql = @"insert into t_stu(name, age, sex) values (?, ?, ?)";
BOOL isSuccess = [self.db executeUpdate: sql, stu. name, @(stu.age), stu.sex];
if (isSuccess) {
NSLog(@"数据插入成功");
}
else {
NSLog(@"数据插入失败");
}
[self.db close];
}
注意:对于FMDB来说它的操作对象必须是OC之中的对象,而不能是C语言之中的int,double的相关类型,所以需要我们将相关内容的用NSNumber进行分装
删除数据
objc
-(void)deleteStu: (NSString *)stuName{
[self createDB];
NSString *sql = @"delete from t_stu where name = ?" ;
BOOL isSuccess = [self.db executeUpdate: sql, stuName];
if (isSuccess) {
NSLog(@"数据删除成功");
} else {
NSLog(@"数据删除失败");
}
[self.db close];
}
更改数据
objc
-(void)updateStu: (Student *)stu{
[self createDB];
NSString *sql = @"update t_stu set age =?, sex =? where name = ?" ;
BOOL isSuccess = [self.db executeUpdate:sql, @(stu.age), stu.sex, stu.name];
if (isSuccess) {
NSLog(@"数据修改成功");
}
else {
NSLog(@"数据修改失败");
}
[self.db close];
}
查询数据
objc
-(NSArray<Student *> *)queryStu:(NSString *)stuName{
[self createDB];
NSMutableArray *stus = [NSMutableArray array];
NSString *sql = @"select age, sex from t_stu where name = ?";
FMResultSet *result = [self.db executeQuery:sql, stuName];
while (result.next) {
NSString *sex = [result stringForColumn :@"sex"];
int age = [result intForColumn:@"age"];
Student *stu = [[Student alloc]initWithName:stuName andAge:age andSex:sex];
[stus addObject: stu];
}
[self.db close];
return stus;
}
总结
这还是一个比较粗糙的FMDB的实用说明,浅层的学习也足够知乎日报项目的实用,后续的相关学习就等知乎日报完成之后在。再进行系统规划吧