所谓的数据库 无非就是进行增删查找的一些操作,在网上看了很多对数据库的封装,但是人家封装的不一定适合自己的项目,还有一个缺点就是,如果使用人家封装的,用的时候觉得还不错,挺好。但是如果有一天忽然发现有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
的软件
百度一下下载一个即可。相信有一定开发经验,以及写过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刷新即可
插入数据
--插入数据如果是字符串加上单引号
insert into User2(name,age,sex) VALUES ('阳阳', 19,'钕')
更新全部值更新
//将表中所有的age设为为100
update User2 set age = 100
/**
其他操作:
将id大于20的 年龄设置为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:存储一些大批量的数据。
优点:
①占用资源低
②处理速度快
不比比了。。。开始撸串串
三、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
例如下图:
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
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(@"清除表中的所有数据失败");
}
}
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
勾选之后进入工程你会发现系统帮我们创建了一个后缀名为” .xcdatamodeld”的文件
方式二:新建一个DataModel文件。名字自己定,创建一个xcdatamodeld文件
有了XX.xcdatamodeld文件后 我们打开,进行如下操作:
最后会生成如下4个文件,创建模型也算是大功告成了
紧接着直接在控制器中导入即可
#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;
}
此时根据后台打印路径前往文件夹打开
查看UserInfo中的定义的属性
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(@"清空所有数据失败");
}