ios - 關(guān)于數(shù)據(jù)持久化不看我看誰(二)

??.png

所謂的數(shù)據(jù)庫 無非就是進(jìn)行增刪查找的一些操作,在網(wǎng)上看了很多對(duì)數(shù)據(jù)庫的封裝,但是人家封裝的不一定適合自己的項(xiàng)目,還有一個(gè)缺點(diǎn)就是,如果使用人家封裝的,用的時(shí)候覺得還不錯(cuò),挺好。但是如果有一天忽然發(fā)現(xiàn)有bug了,改的動(dòng)人家代碼還好,改不動(dòng)就GG了,最好的還是自己的寫一套適合自己項(xiàng)目需求的。

目錄
一、Navicat Premium 的使用
二、SQLite3(待補(bǔ)充)
三、FMDB
3.1 什么是FMDB?
3.2 優(yōu)點(diǎn)
3.3 核心類
3.4 FMDB基本語法
3.5 FMDB基本使用(創(chuàng)建表、增刪改查)
3.6 FMDatabaseQueue基本使用
四、CoreData
4.1 什么是CoreData?
4.2 優(yōu)點(diǎn)
4.3 核心類
4.4 CoreData基本操作
4.5 CoreData基本使用(創(chuàng)建表、增刪改查)

寫這篇文章時(shí),光想了2天該如何動(dòng)手,怎么樣寫才更加清新明了,讓新手一看即懂,讓碼手也能鞏固知識(shí)。在網(wǎng)上找了各種大牛封裝的,其實(shí)也許人家封裝得好,但是有些時(shí)候也許并不適合自己的項(xiàng)目需求,人家封裝的,自己改動(dòng)也麻煩,何不如自己動(dòng)手來一趟。最后決定采取(理論知識(shí)+示例demo+圖片gif)相結(jié)合,這樣使讀者看起來也不至于那么枯燥乏味。筆者在寫這篇文章又花了筆者斷斷續(xù)續(xù)2天的時(shí)間,才整理完畢!


引言
對(duì)數(shù)據(jù)的操作條件是先創(chuàng)建,其次操作(增刪查改),首先先說說Sqlite,得看懂Sqlite語句所表達(dá)的意思。其次再看FMDB,逐步進(jìn)入深化。

其次

不要對(duì)Sqlite產(chǎn)品一種抵抗心理,試著慢慢看下去的心理其實(shí)并不難,其實(shí)我們要掌握的東西其實(shí)不多,無非就創(chuàng)建表,其次便是增刪查改。加一起也就5句語句。多敲幾遍就會(huì)了。其實(shí)Very easy

首先我們先一個(gè)軟件 叫 Navicat Premium的軟件

Navicat Premium.png

百度一下下載一個(gè)即可。相信有一定開發(fā)經(jīng)驗(yàn),以及寫過java的一定知道這是一款什么軟件。簡(jiǎn)單來說就是一款的數(shù)據(jù)庫管理工具。

先大致介紹一下Navicat Premium的使用,怕有些新手看著一臉懵逼的感覺。

一、Navicat Premium 的使用

在創(chuàng)建表之前 首頁我們要了解一個(gè)概念
主鍵(Primary key)用來唯一地標(biāo)識(shí)某一條記錄。粗俗一點(diǎn)來說相當(dāng)一個(gè)人的身份證號(hào)碼,名字可以有相同的,但是身份證號(hào)碼是唯一性的。
主鍵可以是一個(gè)字段或者多個(gè)字段
主鍵的設(shè)計(jì)原則:
主鍵對(duì)用戶是沒有意義的,主鍵不包含動(dòng)態(tài)變化的數(shù)據(jù),是由計(jì)算機(jī)自動(dòng)生成的

創(chuàng)建表

//create  table if exists:如果不存在則創(chuàng)建表
//id integer PRIMARY key AUTOINCREMENT:將id作為主鍵 自動(dòng)增長
//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) 

創(chuàng)建表之后直接選中Tables然后按快捷鍵command+r刷新即可

創(chuàng)建表.gif

插入數(shù)據(jù)

--插入數(shù)據(jù)如果是字符串加上單引號(hào)
insert into User2(name,age,sex) VALUES ('陽陽', 19,'釹') 

圖片.png

更新全部值更新

//將表中所有的age設(shè)為為100
update User2  set age = 100
/**
其他操作:
將id大于20的 年齡設(shè)置為50
*/
//update User2 set age = 55 where id > 20

多插入幾條,再 command+ r 走起

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:存儲(chǔ)一些大批量的數(shù)據(jù)。
優(yōu)點(diǎn):
①占用資源低
②處理速度快
不比比了。。。開始擼串串

三、FMDB

3.1 什么是FMDB?

FMDB是以O(shè)C的方式封裝了Sqlite.使其操作性更加面向?qū)ο蟆?/p>

3.2 優(yōu)點(diǎn)

1.使用起來更加面向?qū)ο?,省去很多C語言代碼
2.提供了多線程安全的數(shù)據(jù)庫操作方法,有效地防止數(shù)據(jù)混亂

3.3 核心類
  • FMDatabase:可以理解成一個(gè)數(shù)據(jù)庫。一個(gè)FMDatabase對(duì)象就代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫,用來執(zhí)行SQL語句
  • FMResultSet:使用FMDatabase執(zhí)行查詢后的結(jié)果集
  • FMDatabaseQueue:用于在多線程中執(zhí)行多個(gè)查詢或更新,它是線程安全的
3.4 FMDB基本語法

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

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

更新(executeUpdate):包括create,update,insert,delete,drop(不區(qū)分大小寫) 都使用executeUpdate

例如下圖:

圖片.png
3.5 FMDB基本使用(創(chuàng)建表、增刪改查)
3.5.1 創(chuàng)建表

創(chuàng)建表之前先設(shè)置數(shù)據(jù)庫路徑,然后再創(chuàng)建表

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

    [super viewDidLoad];
    _userModel = [UserModel new];
    _count = 1;
    //設(shè)置數(shù)據(jù)庫名稱
    NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"User.sqlite"];
    NSLog(@"%@",fileName);
    //2.獲取數(shù)據(jù)庫
    _db = [FMDatabase databaseWithPath:fileName];
    if ([_db open]) {
        NSLog(@"打開數(shù)據(jù)庫成功");
    }else{
        NSLog(@"打開數(shù)據(jù)庫s失敗");
    }    
}
#pragma mark - 創(chuàng)建表
- (IBAction)createOnClick {
    
// CREATE TABLE IF NOT EXIST:表不存在 再創(chuàng)建    AUTOINCREMENT 自動(dòng)增長   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作為主鍵 自動(dòng)增長
    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(@"創(chuàng)建表成功");
    }else{
        NSLog(@"創(chuàng)建表失敗");
    }
}

根據(jù)后臺(tái)打印, 我們復(fù)制路徑然后前往該文件夾。然后使用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
圖片.png
3.5.2 增刪改查
#pragma mark - 添加數(shù)據(jù)
- (IBAction)addDataOnClick {
    NSString *name  = [NSString stringWithFormat:@"%@號(hào)大美釹",@(_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 - 刪除數(shù)據(jù)
- (IBAction)deleteDataOnClick {
    
    BOOL result = [_db executeUpdate:@"delete from User where id = ?",@(5)];

    if (result) {
        NSLog(@"刪除成功");
    }else{
        NSLog(@"刪除失敗");
    }
}
#pragma mark - 查詢數(shù)據(jù)
- (IBAction)queryDataOnClick {
    FMResultSet *resultSet  = [_db executeQuery:@"select * from User"];
//遍歷查詢
    while ([resultSet next]) {
     //拿到每條數(shù)的id
        int idNum = [resultSet intForColumn:@"id"];
        NSString *name = [resultSet objectForColumnName:@"name"];
        int age = [resultSet intForColumn:@"age"];
        NSString *sex = [resultSet objectForColumnName:@"sex"];
        NSLog(@"學(xué)號(hào):%@ 姓名:%@ 年齡:%@ 性別:%@",@(idNum),name,@(age),sex);
    }
}
#pragma mark - 修改數(shù)據(jù)
- (IBAction)changeDataOnClick{
    NSString *newName = @"花花";
    NSString *oldName = @"3號(hào)大美釹";
    
    BOOL result = [_db executeUpdate:@"update User set name = ? where name = ?",newName,oldName];
    
    if (result) {
        NSLog(@"修改成功");
    }else{
        NSLog(@"修改失敗");   
    }   
}
#pragma mark - 清除數(shù)據(jù)
- (IBAction)cleanDataOnClick { 
    BOOL result = [_db executeUpdate:@"drop table if exists User"];
    if (result) {
        
        NSLog(@"清除表中的所有數(shù)據(jù)成功");
    }else{        
        NSLog(@"清除表中的所有數(shù)據(jù)失敗");
    }
}
1234.gif
3.6 FMDatabaseQueue基本使用

FMDatabase是線程不安全的,當(dāng)FMDB數(shù)據(jù)存儲(chǔ)想要使用多線程的時(shí)候,F(xiàn)MDatabaseQueue就派上用場(chǎng)了。執(zhí)行命令的時(shí)候非常方便,直接在一個(gè)block中進(jìn)行操作
例如:

建議對(duì)數(shù)據(jù)庫的操作,最好寫一個(gè)工具類對(duì)數(shù)據(jù)進(jìn)行增刪查改,這里只是寫了一個(gè)簡(jiǎn)單滴創(chuàng)建表的示例,其他的增刪改查的方法仿之寫法即可。
/**********控制器直接調(diào)用**************/

 [[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(@"數(shù)據(jù)庫路徑---%@",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(@"創(chuàng)建表成功");   
        }else{
            NSLog(@"創(chuàng)建表失敗");
        }
    }];
}

四、CoreData

4.1 什么是CoreData?

CoreData:對(duì)SQLite3的一層面向?qū)ο蟮陌b,本質(zhì)上還是轉(zhuǎn)換成對(duì)應(yīng)的SQL語句去執(zhí)行??梢怨芾韺?shí)體以及實(shí)體之間的關(guān)聯(lián)關(guān)系的持久化。

4.2 優(yōu)點(diǎn)
  • 1.不用寫 SQL 語句
  • 2.代碼清晰,如果有語法錯(cuò)誤會(huì)即使提示,而不是等到運(yùn)行時(shí)才知道錯(cuò)誤.
  • 3.可視化的結(jié)構(gòu),讓對(duì)于字段的增刪清晰明朗
  • 4.用于做數(shù)據(jù)持久化,適合做大量的存儲(chǔ)和查詢.
4.3 核心類
  • NSManagedObiectModel(托管對(duì)象模型):

代表CoreData的模型文件

  • NSPeristentStoreCoordinator(持久化存儲(chǔ)協(xié)調(diào)器):

負(fù)責(zé)管理底層的存儲(chǔ)文件,例如SQLite數(shù)據(jù)庫等。

  • NSManagedObjectContext(托管對(duì)象上下文):

負(fù)責(zé)應(yīng)用和數(shù)據(jù)庫之間的交互。例如:應(yīng)用對(duì)實(shí)體所做的任何增、刪、查、改操作都必須通過該對(duì)象來完成

  • NSEntityDescription(實(shí)體描述):

對(duì)象相當(dāng)于實(shí)體的抽象。實(shí)體描述定義了該實(shí)體的名字、實(shí)體的實(shí)現(xiàn)類,并用一個(gè)集合定義了該實(shí)體包含的所有屬性

  • NSFetchRequest(抓取請(qǐng)求):

該對(duì)象封裝了查詢實(shí)體的請(qǐng)求,包括程序需要查詢哪些實(shí)體、查詢條件、排序規(guī)則等。抓取請(qǐng)求定義了本次查詢的實(shí)體的名字、抓取請(qǐng)求的查詢條件,通過NSPredicate來表示,并用一個(gè)NSArray集合定義了所有的排序規(guī)則

4.4 CoreData基本操作

創(chuàng)建有兩種方式

方式一:創(chuàng)建工程時(shí)勾選UserCoreData

圖片.png

勾選之后進(jìn)入工程你會(huì)發(fā)現(xiàn)系統(tǒng)幫我們創(chuàng)建了一個(gè)后綴名為” .xcdatamodeld”的文件

圖片.png

方式二:新建一個(gè)DataModel文件。名字自己定,創(chuàng)建一個(gè)xcdatamodeld文件

圖片.png

有了XX.xcdatamodeld文件后 我們打開,進(jìn)行如下操作:

圖片.png
圖片.png
圖片.png

最后會(huì)生成如下4個(gè)文件,創(chuàng)建模型也算是大功告成了

圖片.png

緊接著直接在控制器中導(dǎo)入即可

#import "UserInfo+CoreDataClass.h"
4.5 CoreData基本使用(創(chuàng)建表、增刪改查)

4.5.1 創(chuàng)建表

//注意:需要導(dǎo)入#import <CoreData/CoreData.h>頭文件
@property(nonatomic,strong)NSManagedObjectContext *context;

- (IBAction)c_createTable{
    //注意創(chuàng)建時(shí)候的后綴用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(@"數(shù)據(jù)庫添加成功");
    }else{
        NSLog(@"數(shù)據(jù)庫添加失敗");
    }
    self.context  = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    self.context.persistentStoreCoordinator = psc;
}

此時(shí)根據(jù)后臺(tái)打印路徑前往文件夾打開

圖片.png

查看UserInfo中的定義的屬性

圖片.png

4.5.2 增刪改查

#pragma mark - 添加數(shù)據(jù)
- (IBAction)c_addDataOnClick{
     //運(yùn)用NSEntityDescription創(chuàng)建NSManagedObject對(duì)象
    UserInfo *user = [NSEntityDescription insertNewObjectForEntityForName:@"UserInfo" inManagedObjectContext:self.context];
    
   user.name = [NSString stringWithFormat:@"%@號(hào)大美釹",@(_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 - 刪除數(shù)據(jù)--->(年齡大于等于5的刪除)
- (IBAction)c_deleteDataOnClick{
    
    //NSFetchRequest:一條查詢請(qǐng)求,相當(dāng)于 SQL 中的select語句
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UserInfo"];
    //NSPredicate:謂詞,指定一些查詢條件,相當(dāng)于 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 - 查詢數(shù)據(jù) --->(查詢數(shù)據(jù)中的所有數(shù)據(jù)并打印)
- (IBAction)c_queryDataOnClick{
    //獲取這個(gè)類
    NSEntityDescription *entity = [NSEntityDescription  entityForName:@"UserInfo" inManagedObjectContext:self.context]; 
    //創(chuàng)建查詢請(qǐng)求
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    //設(shè)置查詢請(qǐng)求的實(shí)體
    [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 - 修改數(shù)據(jù) --->(年齡等于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 - 清除數(shù)據(jù) --->(清空數(shù)據(jù)庫所有數(shù)據(jù))
-(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(@"清空所有數(shù)據(jù)成功"):NSLog(@"清空所有數(shù)據(jù)失敗");
}
操作演示gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.CoreData 1.1 CoreData概述 1)Core data 是數(shù)據(jù)持久存儲(chǔ)的最佳方式 2)Core...
    微春風(fēng)閱讀 4,011評(píng)論 0 10
  • 閱讀完本書,首先給我的感覺是內(nèi)容有點(diǎn)對(duì)不起它的¥59.80定價(jià),全書主要講了兩塊內(nèi)容,一塊是SQLite3,...
    瑞小萌閱讀 3,126評(píng)論 4 33
  • 在程序開發(fā)中,數(shù)據(jù)層永遠(yuǎn)是程序的核心結(jié)構(gòu)之一。我們將現(xiàn)實(shí)事物進(jìn)行抽象,使之變成一個(gè)個(gè)數(shù)據(jù)。對(duì)這些數(shù)據(jù)的加工處理是代...
    sindri的小巢閱讀 16,914評(píng)論 13 85
  • 在程序開發(fā)中,數(shù)據(jù)層永遠(yuǎn)是程序的核心結(jié)構(gòu)之一。我們將現(xiàn)實(shí)事物進(jìn)行抽象,使之變成一個(gè)個(gè)數(shù)據(jù)。對(duì)這些數(shù)據(jù)的加工處理是代...
    帥不過oneS閱讀 742評(píng)論 0 1
  • 忘記了已經(jīng)連續(xù)幾天持續(xù)這樣的陰天。世界變得灰蒙蒙的,人也變得灰突突的,心也變得敏感而悲傷起來。想念陽光的熱烈干脆溫暖。
    眠月站閱讀 630評(píng)論 0 50

友情鏈接更多精彩內(nèi)容