ios - 关于数据持久化不看我看谁(二)

ios - 关于数据持久化不看我看谁(二)_第1张图片
.png

所谓的数据库 无非就是进行增删查找的一些操作,在网上看了很多对数据库的封装,但是人家封装的不一定适合自己的项目,还有一个缺点就是,如果使用人家封装的,用的时候觉得还不错,挺好。但是如果有一天忽然发现有bug了,改的动人家代码还好,改不动就GG了,最好的还是自己的写一套适合自己项目需求的。

目录
一、Navicat Premium 的使用
二、SQLite3(待补充)
三、FMDB
3.1 什么是FMDB?
3.2 优点
3.3 核心类
3.4 FMDB基本语法
3.5 FMDB基本使用(创建表、增删改查)
3.6 FMDatabaseQueue基本使用
四、CoreData
4.1 什么是CoreData?
4.2 优点
4.3 核心类
4.4 CoreData基本操作
4.5 CoreData基本使用(创建表、增删改查)

写这篇文章时,光想了2天该如何动手,怎么样写才更加清新明了,让新手一看即懂,让码手也能巩固知识。在网上找了各种大牛封装的,其实也许人家封装得好,但是有些时候也许并不适合自己的项目需求,人家封装的,自己改动也麻烦,何不如自己动手来一趟。最后决定采取(理论知识+示例demo+图片gif)相结合,这样使读者看起来也不至于那么枯燥乏味。笔者在写这篇文章又花了笔者断断续续2天的时间,才整理完毕!


引言
对数据的操作条件是先创建,其次操作(增删查改),首先先说说Sqlite,得看懂Sqlite语句所表达的意思。其次再看FMDB,逐步进入深化。

其次

不要对Sqlite产品一种抵抗心理,试着慢慢看下去的心理其实并不难,其实我们要掌握的东西其实不多,无非就创建表,其次便是增删查改。加一起也就5句语句。多敲几遍就会了。其实Very easy

首先我们先一个软件 叫 Navicat Premium的软件

Navicat Premium.png

百度一下下载一个即可。相信有一定开发经验,以及写过java的一定知道这是一款什么软件。简单来说就是一款的数据库管理工具。

先大致介绍一下Navicat Premium的使用,怕有些新手看着一脸懵逼的感觉。

一、Navicat Premium 的使用

在创建表之前 首页我们要了解一个概念
主键(Primary key)用来唯一地标识某一条记录。粗俗一点来说相当一个人的身份证号码,名字可以有相同的,但是身份证号码是唯一性的。
主键可以是一个字段或者多个字段
主键的设计原则:
主键对用户是没有意义的,主键不包含动态变化的数据,是由计算机自动生成的

创建表

//create  table if exists:如果不存在则创建表
//id integer PRIMARY key AUTOINCREMENT:将id作为主键 自动增长
//not null :不能为空
CREATE TABLE IF NOT EXISTS User2(id integer PRIMARY key AUTOINCREMENT,name text not null,age real default 1,sex text not null) 

创建表之后直接选中Tables然后按快捷键command+r刷新即可

ios - 关于数据持久化不看我看谁(二)_第2张图片
创建表.gif

插入数据

--插入数据如果是字符串加上单引号
insert into User2(name,age,sex) VALUES ('阳阳', 19,'钕') 

图片.png

更新全部值更新

//将表中所有的age设为为100
update User2  set age = 100
/**
其他操作:
将id大于20的 年龄设置为50
*/
//update User2 set age = 55 where id > 20

多插入几条,再 command+ r 走起

ios - 关于数据持久化不看我看谁(二)_第3张图片
111.gif

删除

--删除age = 5
-- delete from User2 where age = 5

--删除sex为男 且年龄小于20的
-- delete from User2 where sex = '男' and age <20 
--名称不是XXX或年龄不是55
-- delete from User2 where name is not "阳阳" or age != 55

全部删除

delete from User2
112.gif

二、SQLite3

SQlite:存储一些大批量的数据。
优点:
①占用资源低
②处理速度快
不比比了。。。开始撸串串

三、FMDB

3.1 什么是FMDB?

FMDB是以OC的方式封装了Sqlite.使其操作性更加面向对象。

3.2 优点

1.使用起来更加面向对象,省去很多C语言代码
2.提供了多线程安全的数据库操作方法,有效地防止数据混乱

3.3 核心类
  • FMDatabase:可以理解成一个数据库。一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句
  • FMResultSet:使用FMDatabase执行查询后的结果集
  • FMDatabaseQueue:用于在多线程中执行多个查询或更新,它是线程安全的
3.4 FMDB基本语法

查询(executeQuery):除了查询使用executeQuery,其余的使用更新

    FMResultSet *resultSet  = [_db executeQuery:@"select * from User"];

更新(executeUpdate):包括create,update,insert,delete,drop(不区分大小写) 都使用executeUpdate

例如下图:

ios - 关于数据持久化不看我看谁(二)_第4张图片
图片.png
3.5 FMDB基本使用(创建表、增删改查)
3.5.1 创建表

创建表之前先设置数据库路径,然后再创建表

@property(nonatomic,strong) FMDatabase *db;  
@property(nonatomic,assign) NSInteger  count;
- (void)viewDidLoad {

    [super viewDidLoad];
    _userModel = [UserModel new];
    _count = 1;
    //设置数据库名称
    NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"User.sqlite"];
    NSLog(@"%@",fileName);
    //2.获取数据库
    _db = [FMDatabase databaseWithPath:fileName];
    if ([_db open]) {
        NSLog(@"打开数据库成功");
    }else{
        NSLog(@"打开数据库s失败");
    }    
}
#pragma mark - 创建表
- (IBAction)createOnClick {
    
// CREATE TABLE IF NOT EXIST:表不存在 再创建    AUTOINCREMENT 自动增长   NOT NULL 不能为空
//CREATE TABLE User (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL, sex text NOT NULL)
//id integer PRIMARY KEY AUTOINCREMENT 将id作为主键 自动增长
    BOOL result = [self.db executeUpdate:@"CREATE TABLE IF NOT EXISTS User (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL, sex text NOT NULL);"];
    if (result) {
        NSLog(@"创建表成功");
    }else{
        NSLog(@"创建表失败");
    }
}

根据后台打印, 我们复制路径然后前往该文件夹。然后使用Navicat打开User.sqlite.

/Users/love/Library/Developer/CoreSimulator/Devices/418C03C5-5D16-48A5-9499-DB13892EAB2A/data/Containers/Data/Application/EB85DCE1-479D-4F02-95A6-4BBD9840BC64/Documents/User.sqlite
ios - 关于数据持久化不看我看谁(二)_第5张图片
图片.png
3.5.2 增删改查
#pragma mark - 添加数据
- (IBAction)addDataOnClick {
    NSString *name  = [NSString stringWithFormat:@"%@号大美钕",@(_count)];
    NSInteger age = _count;
    NSString *sex = _count%2 ==0 ? @"女":@"男";
    BOOL result = [self.db executeUpdate:@"INSERT INTO User (name,age,sex) VALUES (?,?,?)",name,@(age),sex];
    _count ++;
    result == YES ? NSLog(@"插入成功"):NSLog(@"插入失败");
}
#pragma mark - 删除数据
- (IBAction)deleteDataOnClick {
    
    BOOL result = [_db executeUpdate:@"delete from User where id = ?",@(5)];

    if (result) {
        NSLog(@"删除成功");
    }else{
        NSLog(@"删除失败");
    }
}
#pragma mark - 查询数据
- (IBAction)queryDataOnClick {
    FMResultSet *resultSet  = [_db executeQuery:@"select * from User"];
//遍历查询
    while ([resultSet next]) {
     //拿到每条数的id
        int idNum = [resultSet intForColumn:@"id"];
        NSString *name = [resultSet objectForColumnName:@"name"];
        int age = [resultSet intForColumn:@"age"];
        NSString *sex = [resultSet objectForColumnName:@"sex"];
        NSLog(@"学号:%@ 姓名:%@ 年龄:%@ 性别:%@",@(idNum),name,@(age),sex);
    }
}
#pragma mark - 修改数据
- (IBAction)changeDataOnClick{
    NSString *newName = @"花花";
    NSString *oldName = @"3号大美钕";
    
    BOOL result = [_db executeUpdate:@"update User set name = ? where name = ?",newName,oldName];
    
    if (result) {
        NSLog(@"修改成功");
    }else{
        NSLog(@"修改失败");   
    }   
}
#pragma mark - 清除数据
- (IBAction)cleanDataOnClick { 
    BOOL result = [_db executeUpdate:@"drop table if exists User"];
    if (result) {
        
        NSLog(@"清除表中的所有数据成功");
    }else{        
        NSLog(@"清除表中的所有数据失败");
    }
}
1234.gif
3.6 FMDatabaseQueue基本使用

FMDatabase是线程不安全的,当FMDB数据存储想要使用多线程的时候,FMDatabaseQueue就派上用场了。执行命令的时候非常方便,直接在一个block中进行操作
例如:

建议对数据库的操作,最好写一个工具类对数据进行增删查改,这里只是写了一个简单滴创建表的示例,其他的增删改查的方法仿之写法即可。
/**********控制器直接调用**************/

 [[DBTool shareInstance] createTable];

/**********DBTool类**************/
static DBTool *instance = nil;
+ (instancetype)shareInstance{
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc]init];
    });
    return instance;
}
- (FMDatabaseQueue *)dbQueue{

    if(!_dbQueue){
        _dbQueue = [FMDatabaseQueue databaseQueueWithPath:[self dbPath]];
    }
    return _dbQueue;
}
- (NSString *)dbPath{
    NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"Demo1.sqlite"];
    NSLog(@"数据库路径---%@",dbPath);
    return dbPath;
}

- (void)createTable{
    [self.dbQueue inDatabase:^(FMDatabase *db) {
        BOOL result = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_stu (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL, sex text NOT NULL);"];
        if (result) {
            NSLog(@"创建表成功");   
        }else{
            NSLog(@"创建表失败");
        }
    }];
}

四、CoreData

4.1 什么是CoreData?

CoreData:对SQLite3的一层面向对象的包装,本质上还是转换成对应的SQL语句去执行。可以管理实体以及实体之间的关联关系的持久化。

4.2 优点
  • 1.不用写 SQL 语句
  • 2.代码清晰,如果有语法错误会即使提示,而不是等到运行时才知道错误.
  • 3.可视化的结构,让对于字段的增删清晰明朗
  • 4.用于做数据持久化,适合做大量的存储和查询.
4.3 核心类
  • NSManagedObiectModel(托管对象模型):

代表CoreData的模型文件

  • NSPeristentStoreCoordinator(持久化存储协调器):

负责管理底层的存储文件,例如SQLite数据库等。

  • NSManagedObjectContext(托管对象上下文):

负责应用和数据库之间的交互。例如:应用对实体所做的任何增、删、查、改操作都必须通过该对象来完成

  • NSEntityDescription(实体描述):

对象相当于实体的抽象。实体描述定义了该实体的名字、实体的实现类,并用一个集合定义了该实体包含的所有属性

  • NSFetchRequest(抓取请求):

该对象封装了查询实体的请求,包括程序需要查询哪些实体、查询条件、排序规则等。抓取请求定义了本次查询的实体的名字、抓取请求的查询条件,通过NSPredicate来表示,并用一个NSArray集合定义了所有的排序规则

4.4 CoreData基本操作

创建有两种方式

方式一:创建工程时勾选UserCoreData

ios - 关于数据持久化不看我看谁(二)_第6张图片
图片.png

勾选之后进入工程你会发现系统帮我们创建了一个后缀名为” .xcdatamodeld”的文件

图片.png

方式二:新建一个DataModel文件。名字自己定,创建一个xcdatamodeld文件

ios - 关于数据持久化不看我看谁(二)_第7张图片
图片.png

有了XX.xcdatamodeld文件后 我们打开,进行如下操作:

ios - 关于数据持久化不看我看谁(二)_第8张图片
图片.png
ios - 关于数据持久化不看我看谁(二)_第9张图片
图片.png
ios - 关于数据持久化不看我看谁(二)_第10张图片
图片.png

最后会生成如下4个文件,创建模型也算是大功告成了

ios - 关于数据持久化不看我看谁(二)_第11张图片
图片.png

紧接着直接在控制器中导入即可

#import "UserInfo+CoreDataClass.h"
4.5 CoreData基本使用(创建表、增删改查)

4.5.1 创建表

//注意:需要导入#import 头文件
@property(nonatomic,strong)NSManagedObjectContext *context;

- (IBAction)c_createTable{
    //注意创建时候的后缀用momd
    NSURL *pathurl = [[NSBundle mainBundle]URLForResource:@"DB" withExtension:@"momd"];
    
    NSManagedObjectModel *model  = [[NSManagedObjectModel alloc]initWithContentsOfURL:pathurl];
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:model];
    
    NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"UserInfo.sqlite"];
    
    NSLog(@"____%@",dbPath);
    NSError *error = nil;
    
    NSURL *url = [NSURL fileURLWithPath:dbPath];
   [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil
                             error:&error];
    if (error == nil) {   
        NSLog(@"数据库添加成功");
    }else{
        NSLog(@"数据库添加失败");
    }
    self.context  = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    self.context.persistentStoreCoordinator = psc;
}

此时根据后台打印路径前往文件夹打开

ios - 关于数据持久化不看我看谁(二)_第12张图片
图片.png

查看UserInfo中的定义的属性

ios - 关于数据持久化不看我看谁(二)_第13张图片
图片.png

4.5.2 增删改查

#pragma mark - 添加数据
- (IBAction)c_addDataOnClick{
     //运用NSEntityDescription创建NSManagedObject对象
    UserInfo *user = [NSEntityDescription insertNewObjectForEntityForName:@"UserInfo" inManagedObjectContext:self.context];
    
   user.name = [NSString stringWithFormat:@"%@号大美钕",@(_count)];
    user.age = _count;
    user.sex = _count%2 ==0 ? @"女":@"男";
 
    NSError *savaError = nil;
    BOOL result = [self.context save:&savaError];
   _count ++;
    result == YES ? NSLog(@"插入成功"):NSLog(@"插入失败");
}
#pragma mark - 删除数据--->(年龄大于等于5的删除)
- (IBAction)c_deleteDataOnClick{
    
    //NSFetchRequest:一条查询请求,相当于 SQL 中的select语句
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UserInfo"];
    //NSPredicate:谓词,指定一些查询条件,相当于 SQL 中的where
    NSPredicate *predicate  = [NSPredicate predicateWithFormat:@"age>=%d",5];
    fetchRequest.predicate = predicate;
    NSError *error = nil;
    NSArray *arrResult  = [self.context executeFetchRequest:fetchRequest error:&error];
    
    if (arrResult.count >0) {
        for (UserInfo *user in arrResult) {
            NSLog(@"%zd",user.age);
            [self.context deleteObject:user];
        }
     BOOL result =   [self.context save:nil];
        result == YES? NSLog(@"删除成功"):NSLog(@"删除失败");   
    }
}
#pragma mark - 查询数据 --->(查询数据中的所有数据并打印)
- (IBAction)c_queryDataOnClick{
    //获取这个类
    NSEntityDescription *entity = [NSEntityDescription  entityForName:@"UserInfo" inManagedObjectContext:self.context]; 
    //创建查询请求
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    //设置查询请求的实体
    [fetchRequest setEntity:entity];
    NSArray *arrResult = [self.context executeFetchRequest:fetchRequest error:nil];
    for (UserInfo *user in arrResult) {
        NSLog(@"名字是:%@ 性别是:%@ 年龄是:%zd",user.name,user.sex,user.age);
    }
}
#pragma mark - 修改数据 --->(年龄等于2的改成等于1000)
- (IBAction)c_changeDataOnClick{
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UserInfo"];
    NSPredicate *predicate  = [NSPredicate predicateWithFormat:@"age=%d",2];
    fetchRequest.predicate = predicate;
    NSError *error = nil;
    NSArray *arrResult  = [self.context executeFetchRequest:fetchRequest error:&error];
    for (UserInfo *user in arrResult) {
        NSLog(@"%zd",user.age);
        user.age = 1000;
    }
   BOOL result  =   [self.context save:&error];
    result == YES? NSLog(@"修改成功"):NSLog(@"修改失败");
}

#pragma mark - 清除数据 --->(清空数据库所有数据)
-(IBAction)c_cleanDataOnClick{
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UserInfo"];
    
    NSError *error = nil;
    NSArray *arrResult  = [self.context executeFetchRequest:fetchRequest error:&error];
    for (UserInfo *user in arrResult) {
        [self.context deleteObject:user];
    }
   BOOL  result =  [self.context save:&error];
    result == YES? NSLog(@"清空所有数据成功"):NSLog(@"清空所有数据失败");
}
操作演示gif

你可能感兴趣的:(ios - 关于数据持久化不看我看谁(二))