
所謂的數(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的軟件

百度一下下載一個(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刷新即可

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

更新全部值更新
//將表中所有的age設(shè)為為100
update User2 set age = 100
/**
其他操作:
將id大于20的 年齡設(shè)置為50
*/
//update User2 set age = 55 where id > 20
多插入幾條,再 command+ r 走起

刪除
--刪除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

二、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
例如下圖:

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

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ù)失敗");
}
}

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

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

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

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



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

緊接著直接在控制器中導(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)打印路徑前往文件夾打開

查看UserInfo中的定義的屬性

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ù)失敗");
}
