美文网首页
本地化存储

本地化存储

作者: 火焰与柠檬 | 来源:发表于2016-07-09 23:28 被阅读0次

    SQL基本操作

    1.create 和 drop
    • create table 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;

    • create table t_student (id integer, name text, age integer, score real) ;

    • create table if not exists 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;

    2.增、改、删
    insert
    • insert into 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …) ;

    • insert into t_student (name, age) values (‘mj’, 10) ;

    update
    • update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值, … ;

    • update t_student set name = ‘jack’, age = 20 ;

    delete
    • delete from 表名 ;

    • delete from t_student ;

    数据类型

    SQLite将数据划分为以下几种存储类型:

    • integer : 整型值

    • real : 浮点值

    • text : 文本字符串

    • blob : 二进制数据(比如文件)

    • SQLite是无类型的,就算声明为integer类型,还是能存储字符串文本(主键除外)。
      建表时声明啥类型或者不声明类型都可以,也就意味着创表语句可以这么写:

      create table t_student(name, age);

    • 数据库中的字符串内容应该用单引号 ’ 括住

    条件语句

    where
    • where 字段 = 某个值 ; // 不能用两个 =

    • where 字段 is 某个值 ; // is 相当于 =

    • where 字段 != 某个值 ;

    • where 字段 is not 某个值 ; // is not 相当于 !=

    • where 字段 > 某个值 ;

    • where 字段1 = 某个值 and 字段2 > 某个值 ; // and相当于C语言中的 &&

    • where 字段1 = 某个值 or 字段2 = 某个值 ; // or 相当于C语言中的 ||

    例子:

    (1)将t_student表中年龄大于10 并且 姓名不等于jack的记录,年龄都改为 5

    update t_student set age = 5 where age > 10 and name != ‘jack’ ;
    

    (2)删除t_student表中年龄小于等于10 或者 年龄大于30的记录

    delete from t_student where age <= 10 or age > 30 ;
    

    (3)将t_student表中名字等于jack的记录,score字段的值 都改为 age字段的

    update t_student set score = age where name = ‘jack’ ;
    
    select
    • select 字段1, 字段2, … from 表名 ;

        select name, age from t_student ;
      
        select * from t_student where age > 10 ;  //  条件查询
      
    • select 字段1 别名 , 字段2 别名 , … from 表名 别名 ;

        select name myname, age myage from t_student s;
      
        select s.myname, s.myage from t_student s ;
      
    • 计算记录的数量

      select count (字段) from 表名 ;

        select count (age) from t_student ;
      

      select count ( * ) from 表名 ;

        select count ( * ) from t_student where score >= 60;
      
    • 排序

      select * from t_student order by 字段 ;

        select * from t_student order by age ;
      
        select * from t_student order by age desc ;  //降序
        
        select * from t_student order by age asc ;   // 升序(默认)
      

      先按照年龄排序(升序),年龄相等就按照身高排序(降序)

        select * from t_student order by age asc, height desc ;
      
    limit(精准查询)
    • select * from 表名 limit 数值1, 数值2 ;

       select * from t_student limit 4, 8 ;//跳过最前面4条语句,然后取8条记录
       
       select * from t_student limit 7 ;//这条语句的作用相当于select * from t_student limit 0, 7 ;表示取最前面的7条记录
      
    • limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据

      第1页:limit 0, 5

      第2页:limit 5, 5

      第3页:limit 10, 5

      第n页:limit 5*(n-1), 5

    约束

    简单约束
    • not null :规定字段的值不能为null

    • unique :规定字段的值必须唯一

    • default :指定字段的默认值

        create table t_student (id integer, name text not null unique, age integer not null default 1) ;//name字段不能为null,并且唯一;age字段不能为null,并且默认为1
      
    主键约束
    • 主键:每张表里都需要有一个字段,来保证数据的唯一性;

    • 主键可以是一个字段或多个字段;

    • 主键应当是对用户没有意义的

    • 永远也不要更新主键

    • 主键不应包含动态变化的数据

    • 主键应当由计算机自动生成

    • 声明主键

        create table t_student (id integer primary key autoincrement, name text, age integer) ;//primary key,就说明是一个主键字段;如果想要让主键自动增长(必须是integer类型),应该增加autoincrement
      
    外键约束
    • 外键:一张表的某个字段,引用着另一张表的主键字段,用来建立表与表之间的联系。

        create table t_student (id integer primary key autoincrement, name text, age integer, class_id integer, constraint fk_student_class foreign key (class_id) references t_class (id));//t_student表中有一个叫做fk_t_student_class的外键; 这个外键的作用是用t_student表中的class_id字段引用t_class表的id字段
      
    表连接查询
    • 表连接:需要联合多张表才能查询到数据。

    • 内连接:inner join 或者 join (显示的是左右表都有完整字段值的记录)

    • 左外连接:left outer join (保证左表数据的完整性)

        select s.name,s.age from t_student s, t_class c where s.class_id = c.id and c.name = ‘0316iOS’;//查询0316iOS班的所有学生的姓名和年龄
      

    FMDB

    主要的类
    • FMDatabase – 表示一个单独的SQLite数据库。 用来执行SQLite的命令;

    • FMResultSet – 表示FMDatabase执行查询后结果集;

    • FMDatabaseQueue – 如果你想在多线程中执行多个查询或更新,你应该使用该类。这是线程安全的;

    创建数据库
    FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
    
    • 该文件路径无需真实存,如果不存在会自动创建;

    • 空字符串(@”")。表示会在临时目录创建一个空的数据库,当FMDatabase 链接关闭时,文件也被删除;

    • NULL. 将创建一个内在数据库。同样的,当FMDatabase连接关闭时,数据会被销毁;

    打开数据库

    与数据库交互前,必须先打开数据库,如果资源或权限不足,将会打开失败。

    if (![db open]) {    
            [db release];   
            return;    
        }  
    
    执行更新

    一切不是select的命令都是更新命令。执行更新会返回一个BOOL值。YES表示执行成功,否则有错误。相关方法:

    • -lastErrorMessage

    • -lastErrorCode

    使用executeUpdate:执行更新

    -(BOOL)executeUpdate:(NSString*)sql, ...

    -(BOOL)executeUpdateWithFormat:(NSString*)format, ...

    -(BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments

    示例:

    [db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"]
    
    [db executeUpdateWithFormat:@"INSERT INTO t_shop(name, price) VALUES (%@, %f);", shop.name, shop.price];
    

    注意:参数必须是对象类型。比如要把int型变成NSNumber对象;

    SQL中使用%要用%%;

    执行查询

    select命令,执行方法是以-excuteQuery开头的。

    • 成功返回FMResultSet对象, 错误返回nil;

    • 支持使用NSError**参数

    • -lastErrorMessage

    • -lastErrorCode

    使用executeQuery:执行更新

    -(FMResultSet *)executeQuery:(NSString*)sql, ...

    -(FMResultSet *)executeQueryWithFormat:(NSString*)format, ...

    -(FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments

    示例:

    // 查询数据
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
    
    // 遍历结果集
    while ([rs next]) {
        NSString *name = [rs stringForColumn:@"name"];
        int age = [rs intForColumn:@"age"];
        double score = [rs doubleForColumn:@"score"];
    }
    
    类型转换

    参数是查询结果集的列的索引位置

    • intForColumn:
    • longForColumn:
    • longLongIntForColumn:
    • boolForColumn:
    • doubleForColumn:
    • stringForColumn:
    • dataForColumn:
    • dataNoCopyForColumn:
    • UTF8StringForColumnIndex:
    • objectForColumn:

    你无需调用 [FMResultSet close]来关闭结果集, 当新的结果集产生,或者其数据库关闭时,会自动关闭。

    关闭数据库

    使用完数据库后,关闭数据库连接来释放SQLite资源。

    [db close]
    
    事务和多线程

    事务:是执行多个SQL语句时,如果有一个失败了,则回滚到原始状态。主要用来确保所有的SQL逻辑必须完成。

    多线程:如果多个线程同时访问FMDatabase实例,会造成混乱,所以要用FMDatabaseQueue:

    • FMDatabaseQueue的创建
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
    
    • 简单使用
    [queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
        
        FMResultSet *rs = [db executeQuery:@"select * from t_student"];
        while ([rs next]) {
            // …
        }
    }];
    
    • 轻松地把简单任务包装到事务里
    [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
        [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
        
        FMResultSet *rs = [db executeQuery:@"select * from t_student"];
        while ([rs next]) {
            // …
        }
    }];
    
    事务回滚
    *rollback = YES;
    

    NSUserDefault

    NSUserDefault:是一个单例,在整个程序中,只有一个实例对象,可以用于数据的永久保存,且简单实用,这是他可以让数据自由传递的一个前提(可以存储用户信息,夜间模式,字体大小)

    其实存储后也是一个plist文件。

    存储基本数据类型
    • NSNumber(NSInteger,float,double)

    • NSString,NSArray,NSDictionary,BOOL

    示例:

    //使用NSUserDefault进行存储
    //1:创建要存储的数组
    NSArray *array = @[@"11", @"22",@"33"];
    //创建NSUserDefault对象
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    [user setObject:array forKey:@"userArray"];
    NSLog(@"%@",user);
    
    //读取
    NSArray *newarr = [user objectForKey:@"userArray"];
    NSLog(@"%@",newarr);
    

    存储的对象必须是不可变,如果要存储可变的数组和字典,应该先转换成不可变的之后再存储。

    存储自定义对象
    • 对象要遵守NSCoding协议、copy协议,进行归档、解档
    //归档
    -(void)encodeWithCoder:(NSCoder *)aCoder{
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char * propertyCsString = property_getName(properties[i]);
            NSString   * propertyName  =  [NSString stringWithCString:propertyCsString encoding:NSUTF8StringEncoding];
            id           propertyValue =  [self valueForKey:propertyName];
            [aCoder encodeObject:propertyValue forKey:propertyName];
        }
        free(properties);
    }
    //解档
    -(instancetype)initWithCoder:(NSCoder *)aDecoder{
        self = [super init];
        if (self) {
            unsigned int count;
            objc_property_t *properties = class_copyPropertyList([self class], &count);
            for (int i = 0; i < count; i++) {
                const char *property_csNam = property_getName(properties[i]);
                NSString   *p_key = [NSString stringWithCString:property_csNam encoding:NSUTF8StringEncoding];
                id value = [aDecoder decodeObjectForKey:p_key];   
                [self setValue:value forKey:p_key];
            }   
            free(properties);
        } 
    return self
    } 
    
    
     ///copy 协议
    -(id)copyWithZone:(NSZone *)zone{
        StudentModel *s_model = [[self copyWithZone:zone] init];
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char *propertyCS = property_getName(properties[i]);
            NSString *p_key = [NSString stringWithCString:propertyCS encoding:NSUTF8StringEncoding];
            id p_value = [self valueForKey:p_key];
            [s_model setValue:p_value forKey:p_key];
        }
        free(properties);
        return s_model;
    }  
    
    • 转换成NSData再进行存储
        StudentModel *s_model = [[StudentModel alloc] init];
        s_model.s_name = @"xiaoqiang";
        s_model.s_id = @"22";
        s_model.s_password = @"123456";
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:s_model];
        [u_default setObject:data forKey:@"s_student"];
        [u_default synchronize];
        NSData *rachiverData = [u_default objectForKey:@"s_student"];
        StudentModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:rachiverData];
        NSLog(@"\n name is %@ \n id is %@ \n password is %@",model.s_name,model.s_id,model.s_password);
    

    调用 synchronize 立刻同步数据到文件内,不然会有延迟。

    [mySettingData synchronize];
    
    删除对应的key
    - (void)removeObjectForKey:(NSString *)defaultName;
    //或者 
    [[NSUserDefaults ] setObject:nil]
    

    Plist

    主要用来存储大文件。

    缺点:需要将所有的数据取出再全部保存。

    存储基本数据类型(array,dictionary,string,bool,date,data)
    • 存入字典和数组
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    
    [dict writeToFile:@"filePath" atomically:YES];
    
    NSMutableArray *array = [NSMutableArray array];
    
    [array writeToFile:@"filePath" atomically:YES];
    
    • 读取数组和字典
    //方法1:
    NSString *filePath=[[NSBundle mainBundle] pathForResource:@"myDict" ofType:@"plist"];  
    NSDictionary *myDic = [[NSDictionary alloc]initWithContentsOfFile:filePath];
    
    NSString *filePath=[[NSBundle mainBundle] pathForResource:@"myArr" ofType:@"plist"];
    NSArray *myArr2 = [[NSArray alloc] initWithContentsOfFile:filePath];
    
    //方法2:
     NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
     NSString *filePath = [docPath stringByAppendingPathComponent: @"myData.plist"];
           
     NSDictionary *infoDic = [NSDictionary dictionaryWithContentsOfFile: filePath];
    
    存储自定义数据类型
    • 也要实现归档协议然后转换成NSData类型储存
    NSString *path = [self getPlistLibraryWithSuffix:@"test.plist"];
    
        NSMutableArray *stu_array = [NSMutableArray new];
    
        for (int i = 0; i < 10; i ++) {
    
            StudentModel *s_model = [StudentModel new];
    
            s_model.s_name = [NSString stringWithFormat:@"name%d",i];
            s_model.s_id = [NSString stringWithFormat:@"%d",100 + i];
            s_model.s_password = @"123456";
            [stu_array addObject:s_model];
        }
    ///写入
        NSData *archiverData = [NSKeyedArchiver archivedDataWithRootObject:stu_array];
        BOOL isSuc = [archiverData writeToFile:path atomically:YES];
    //  BOOL isSuc = [NSKeyedArchiver archiveRootObject:stu_array toFile:path];
        NSLog(@"%d",isSuc);
    
      ///读取
        NSData *unarchiverData = [NSData dataWithContentsOfFile:path];
        NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithData:unarchiverData];
    //  NSArray *unArchiverArr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];    
        NSLog(@"%@==",unArchiverArr);
    
    删除plist文件
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    if ([fileManager isExecutableFileAtPath:@"filePath"]) {
    
        NSError *error;
    
        [fileManager removeItemAtPath:@"filePath" error:&error];
    }
    

    沙盒

    沙盒的结构

    总结:

    • Document 保存用户生成的数据(会备份)

    • Library/Cache 保存服务器数据或日志(不会备份)

    • temp 保存临时数据、经常要删除的

    相关操作
    • 获取路径
    //Document
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    //library
    NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
    //cache
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    //temp
    NSString *tempPath =  NSTemporaryDirectory();
    
    • 创建目录、创建文件
    //document path
    NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    //test path
    NSString *testPath= [documentsPath stringByAppendingPathComponent:@"test"];
    //file path 
    NSString *filePath = [testPath stringByAppendingString:@"file.plist"];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    // 创建目录
    [fileManager createDirectoryAtPath:testPath withIntermediateDirectories:YES attributes:nil error:nil];
    // 创建文件
    [fileManager createFileAtPath:filePath contents:nil attributes:nil];
    
    • 获取目录下的所有文件名
    NSArray *fileNameArrray = [fileManager subpathsOfDirectoryAtPath:documentsPath error:nil];
    
    //可能目录比较深,耗性能
    NSArray *fileNameArrray =  [fileManager subpathsAtPath:documentsPath];
    
    • 更改到当前目录操作
    //之后都在document文件夹中操作
    [fileManager changeCurrentDirectoryPath:documentsPath];
    
    • 删除目录、删除文件(将其移动到temp目录)
    //删除目录
    [fileManager removeItemAtPath:documentsPath error:nil];
    //删除文件
    [fileManager removeItemAtPath:filePath error:nil];
    
    • 写入数据
    NSString *temp = @"nihao 世界";
    int dataInt = 1234;
    float dataFloat = 3.14f;
    //创建数据缓冲
    NSMutableData *writer = [[NSMutableData alloc] init];
    //将字符串添加到缓冲中
    [writer appendData:[temp dataUsingEncoding:NSUTF8StringEncoding]];   
    //将其他数据添加到缓冲中
    [writer appendBytes:&dataInt length:sizeof(dataInt)];
    [writer appendBytes:&dataFloat length:sizeof(dataFloat)];  
    //将缓冲的数据写入到文件中
    [writer writeToFile:path atomically:YES]; 
    
    • 读取数据
    int intData;
    float floatData = 0.0;
    NSString *stringData;
        
    NSData *reader = [NSData dataWithContentsOfFile:path];
    stringData = [[NSString alloc] initWithData:[reader subdataWithRange:NSMakeRange(0, [temp length])]
                                   encoding:NSUTF8StringEncoding];
    [reader getBytes:&intData range:NSMakeRange([temp length], sizeof(intData))];
    [reader getBytes:&floatData range:NSMakeRange([temp length] + sizeof(intData), sizeof(floatData))];
    NSLog(@"stringData:%@ intData:%d floatData:%f", stringData, intData, floatData);
    

    引用文章

    参考NSUserDefault、Plist的解档和归档
    FMDB的使用
    本地数据持久化简述

    相关文章

      网友评论

          本文标题:本地化存储

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