美文网首页iOS 好东西数据缓存iOS开发技术
ios - 关于数据持久化不看我看谁(二)

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

作者: flowerflower | 来源:发表于2018-01-29 00:10 被阅读1114次
    📚.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刷新即可

    创建表.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 走起

    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

    例如下图:

    图片.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
    
    图片.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

    图片.png

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

    图片.png

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

    图片.png

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

    图片.png 图片.png 图片.png

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

    图片.png

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

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

    4.5.1 创建表

    //注意:需要导入#import <CoreData/CoreData.h>头文件
    @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;
    }
    

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

    图片.png

    查看UserInfo中的定义的属性

    图片.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 - 关于数据持久化不看我看谁(二)

      本文链接:https://www.haomeiwen.com/subject/tzrvaxtx.html