iOS Sqlite数据库的使用

简介: iOS Sqlite数据库的使用

总体内容


1、sqlite基本操作封装

2、动态建表-基本创建

3、动态建表-忽略字段

4、动态更新表-迁移数据

5、保存/更新模型

6、删除模型

7、查询模型

8、模型中-字典/数组属性处理

9、存在问题的优化方案

10、上面所有步骤组合起来的JKSqliteKit的使用


一、sqlite基本操作封装



  • 1.1、创建项目,导入 libsqlite3.0.tbd



image.png

  • 1.2、打开数据库
  • <1>、获取数据库的名字


NSString *sqliteName = @"jk_common.sqlite";
if (sqliteName.length != 0) {
     sqliteName = [NSString stringWithFormat:@"jk_%@.sqlite",uid];
}


提示:数据库的名字我们采取 用户机制,操作数据库,共同的数据库,也就是未登录状态,统一使用 jk_common.sqlite数据库,登陆后,根据用户的id创建对应的数据库:jk_(用户id).sqlite


  • <2>、对应的路径(我们把对一个的数据库放到了/Library/Caches下)


NSString *sqlitePath = [JKSqliteCachePath stringByAppendingPathComponent:sqliteName];


提示:JKSqliteCachePath 是一个宏:#define JKSqliteCachePath [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Caches"]


  • <3>、打开数据库,不存在的情况下自动创建


sqlite3 *ppDb = nil;
if (sqlite3_open(sqlitePath.UTF8String, &ppDb) != SQLITE_OK) {
     // 打开数据库失败
     return NO;
}
  • 1.3、关闭数据库


// 关闭数据库
sqlite3_close(ppDb);
  • 1.4、执行语句( DDL(增、删、改)DDL(表格操作):返回执行结果)


// 执行sql语句
/**
   第1个参数:数据库对象
   第2个参数:sql语句
   第3个参数:查询时候用到的一个结果集闭包
   第4个参数:用不到
   第5个参数:用不到
 */
 BOOL result = sqlite3_exec(ppDb, sql.UTF8String, nil, nil, nil) == SQLITE_OK;
  • 1.5、查询语句(DQL:返回结果集),核心代码如下


/**
 查询数据
 @param sql sql 语句
 @param uid 用户的id
 @return 字典组成的数组,每一个字典都是一行记录
*/
+(NSMutableArray <NSMutableDictionary *>*)querySql:(NSString *)sql witUid:(NSString *)uid{
   // 1.打开数据库
   If (![self openDB:uid]) {
       NSLog(@"打开失败");
       return nil;
   }
   // 准备语句,预处理语句
   // 2.创建准备语句
   /**
      第1个参数:一个已经打开的数据库对象
      第2个参数:sql语句
      第3个参数:参数2中取出多少字节的长度,-1 自动计算,\0停止取出
      第4个参数:准备语句
      第5个参数:通过参数3,取出参数2的长度字节之后,剩下的字符串
    */
   sqlite3_stmt *ppStmt = nil;
   if (sqlite3_prepare_v2(ppDb, sql.UTF8String, -1, &ppStmt, nil) != SQLITE_OK) {
        NSLog(@"准备语句编译失败");
        return nil;
   }
   // 2.绑定数据(可以有 ? 的省略)
   // 3.执行
   // 大数组 : SQLITE_ROW代表数据的不断的向下查找
   NSMutableArray *rowDicArray = [NSMutableArray array];
   while (sqlite3_step(ppStmt) == SQLITE_ROW) {
         // 一行记录 -> 字典
         // 记录值的字典
         NSMutableDictionary *rowDictionary = [NSMutableDictionary dictionary];
         // 3.1、获取所有列的个数
         int columnCount = sqlite3_column_count(ppStmt);
         // 3.2、遍历所有的列
         for (int i=0; i<columnCount; i++) {
            // 3.2.1、获取所有列的名字,也就是表中字段的名字
            // C语言的字符串
            const char *columnNameC = sqlite3_column_name(ppStmt, i);
            // 把 C 语言字符串转为 OC
            NSString *columnName = [NSString stringWithUTF8String:columnNameC];
            // 3.2.2、获取列值
            // 不同列的类型,使用不同的函数,进行获取值
            // 3.2.2.1、获取列的类型
            int type = sqlite3_column_type(ppStmt, i);
            /** 我们使用的是 SQLite3,所以是:SQLITE3_TEXT
              SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not
              SQLITE_INTEGER  1
              SQLITE_FLOAT    2
              SQLITE3_TEXT    3
              SQLITE_BLOB     4
              SQLITE_NULL     5
             */
             // 3.2.2.2、根据列的类型,使用不同的函数,获取列的值
             id value = nil;
             switch (type) {
                  case SQLITE_INTEGER:
                      value = @(sqlite3_column_int(ppStmt,i));
                      break;
                  case SQLITE_FLOAT:
                      value = @(sqlite3_column_double(ppStmt, i));
                      break;
                  case SQLITE3_TEXT:
                      value = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(ppStmt, i)];
                      break;
                  case SQLITE_BLOB:
                      value = CFBridgingRelease(sqlite3_column_blob(ppStmt, i));
                      break;
                  case SQLITE_NULL:
                      value = @"";
                      break;
                  default:
                      break;
           }
            // 字典填值
            [rowDictionary setValue:value forKey:columnName];
         }
        // 每一个添加到数组中
        [rowDicArray addObject:rowDictionary];
     }
     // 4.重置(省略)
    // 5.释放资源
    sqlite3_finalize(ppStmt);
    // 6.关闭数据库
    [self closeDB];
    return rowDicArray;
}


二、sqlite 数据库动态建表-基本创建



  • 2.1、当我们建立一个model模型的时候,一类名为表名,以成员变量的名字为字段名,成员变量的类型为 sqlite 的类型,从而动态的创建表,如下的模型


image.png

  • 2.2、创建表的 sql 语句合成目标sql语句:create table if not exists 表名(字段1 字段1类型(约束),字段2 字段2类型(约束),字段3 字段3类型(约束),.....,primary(字段))
  • <1>、获取表名


+(NSString *)tableName:(Class)cls{
      // 把类转化为类名的字符串
      return NSStringFromClass(cls); 
}
  • <2>、判断模型里面是否有主键(定义一个协议,让用户设置主键),协议是:JKSqliteProtocol.h里面


if (![cls respondsToSelector:@selector(primaryKey)]) 
{
      NSLog(@"请设置模型里面的主键,遵守协议,实现+(NSString *)primaryKey;,d从而得到主键信息");
      return NO;
}
  • <3>、拼接字段与对应类型的字符串(如:字段1 字段1类型(约束),字段2 字段2类型(约束),字段3 字段3类型(约束),.....,),可以参考demo里面的 JKSqliteModelTool


提示:技术点是:利用runtime获取一个类的成员变量,根据成员变量不同的类型转换成sqlite里面的类型,再把它们合成sql语句类里面字段的 语句


  • 获取一个模型里面所有的字段名字,以及类型


+(NSDictionary *)classIvarNameTypeDictionary:(Class)cls{
     NSMutableDictionary *nameTypeDictionary = [NSMutableDictionary dictionary];
      // 获取所有的成员变量
      unsigned int  outCount = 0;
      Ivar *varList = class_copyIvarList(cls, &outCount);
      for (int i = 0; i<outCount; ++i) {
          Ivar ivar = varList[I];
          // 1.获取成员变量名字
          NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
          if ([ivarName hasPrefix:@"_"]) {
               // 把 _ 去掉,读取后面的
               ivarName = [ivarName substringFromIndex:1];
           }
          // 2.获取成员变量类型
          NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
          // 把包含 @\" 的去掉,如 "@\"NSString\"";-> NSString
          ivarType = [ivarType stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"@\""]];
          NSLog(@"ivarType=%@",ivarType);
          // 3.成员变量的类型可能重复,成员变量的名字不会重复,所以以成员变量的名字为key
          [nameTypeDictionary setValue:ivarType forKey:ivarName];
       }
    return nameTypeDictionary;
}
  • 获取一个模型里面所有的字段名字,以及类型(类型转换为sqlite里面的类型)


+(NSDictionary *)classIvarNameSqliteTypeDictionary:(Class)cls{
     NSMutableDictionary *dict = [[self classIvarNameTypeDictionary:cls] mutableCopy];
     NSDictionary *typeDict = [self switchOCTypeToSqliteTypeDict];
     [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) {
          // 字典
          dict[key] = typeDict[obj];
     }];
   return dict;
}
  • 把上面两个方法合成的字段组合成sql语句里面的 字段


+(NSString *)columnNamesAndTypesStr:(Class)cls{
     NSDictionary *dict = [self classIvarNameSqliteTypeDictionary:cls];
     NSMutableArray *result = [NSMutableArray array];
     [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) {
         [result addObject:[NSString stringWithFormat:@"%@ %@",key,obj]];
     }];
     return [result componentsJoinedByString:@","];
}


三、动态建表-忽略字段



  • 3.1、在定义的协议里面设置,必须实现的方法和可以不用实现的方法,如下:


#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol JKSqliteProtocol <NSObject>
// 主键
@required // 必须实现的方法
+(NSString *)primaryKey;
@optional // 可以不用实现的方法
+(NSArray *)ignoreColumnNames;
@end
NS_ASSUME_NONNULL_END
  • 3.2、模型类里面实现协议方法,以demo里面的 Student类为例


#import "Student.h"
@implementation Student
+(NSString *)primaryKey{
    return @"studentNumber";
}
// 实现要在动态创建表的时候要忽略的字段
+(NSArray *)ignoreColumnNames{
    return @[@"testName"];
}
@end
  • 3.3、在动态创建表创建表的方法里面实现过滤忽略字段在 JKSqliteModel里面的 +(NSDictionary *)classIvarNameTypeDictionary:(Class)cls方法类里面
  • 先判断模型有没有实现忽略方法,有的话取出来


NSArray *ignoreNamesArray = nil;
if ([cls respondsToSelector:@selector(ignoreColumnNames)]) {
     ignoreNamesArray = [cls ignoreColumnNames];
}
  • 判断遍历的成员变量是否包含在数组里面,在里面就 continue 过滤


// 1.1、查看有没有忽略字段,如果有就不去创建(根据自己模型里面是否设置了忽略字段)
if ([ignoreNamesArray containsObject:ivarName]) {
     continue;
}


四、动态更新表-迁移数据



  • 4.1、检测表格是否需要更新(在类 JKSqliteTableTool 里面)
    判断是否更新表格的依据:获取 model (模型)所有的成员变量名数组与表格里面所有的字段组成的数据进行对比,前提是二者的数组都进行过排序,利用数组 isEqualToArray 判断,核心代码如下


+(BOOL)isUpdateTable:(Class)cls uid:(NSString *)uid{
    // 1.获取模型里面的所有成员变量的名字
    NSArray *modelNames = [JKSqliteModel allTableSortedIvarNames:cls];
    // 2.获取uid对应数据库里面对应表的字段数组
    NSArray *tableNames = [JKSqliteTableTool tableColumnNames:cls uid:uid];
    // 3.判断两个数组是否相等,返回响应的结果,取反:相等不需要更新,不相等才需要去更新
    return ![modelNames isEqualToArray:tableNames];
}


提示:上面两个数组的获取都很有学习意义,建议看着demo读这篇博客


  • 4.2、动态迁移数据思路:由于sqlite 是阉割版的,虽然sql语句有删除字段的操作,但是在xcode中不奏效,只有采用如下的方法来解决表更新字段的问题,代码在 JKSqliteModelTool+(BOOL)updateTable:(Class)cls uid:(NSString *)uid里面


  • <1>、根据新模型创建临时表
  • <2>、把就表中的主键数据插入临时表
  • <3>、临时表中的字段有在旧表中的,根据两表主键相等把旧表数据导入临时表
  • <4>、删除旧表,并把临时表名改为旧表名


提示:上面的方法其实就是在用户无察觉的情况下完成了偷梁换柱


  • 4.3、字段改名
  • 通过协议获取改名的映射字典


@optional // 更新字段: 新字段名字 到 旧字段名字 的映射表(字典的key是新字段,字典的value是旧字段)
+(NSDictionary *)updateFieldNewNameReplaceOldName;
  • 在模型里面实现方法(用 studentAge1 字段替换 studentAge 字段)


+(NSDictionary *)updateFieldNewNameReplaceOldName{
      return @{@"studentAge1":@"studentAge"};
}
  • 迁移数据时, 进行过滤


// 获取更名字典
NSDictionary *newNameReplaceOldNameDict = @{};
if ([cls respondsToSelector:@selector(updateFieldNewNameReplaceOldName)]) {
      newNameReplaceOldNameDict = [cls updateFieldNewNameReplaceOldName];
}

提示:在执行 动态迁移数据 这块会有很多的 sql 语句,为了保证都执行成功才是成功,我们可以用 事务 来解决,具体的代码可以看 JKSqliteDatabase 类,对数据库的操作


五、保存/更新模型



  • 5.1、思路分析
    要保存一个模型的数据:1、要先判断这个模型对应的表是否存在;2、不存在的话创建表,存在就判断是否需要更表是否需要更新;3、按照模型主键查看当前主键下的数据是否存在,存在的话就根据主键值更新数据,不存在的话就插入数据
  • 5.2、具体的步骤代码如下,具体的可以参考JKSqliteModelTool里面的 +(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid;方法,核心代码如下


+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid{
   // 用户在使用的过程中直接调用这个方法,来保存模型
   Class cls = [model class];
   // 1、判断表格是否存在,不存在就去创建
   if (![JKSqliteTableTool isTableExists:cls uid:uid]) {
         // 创建表格
         if (![self createTable:cls uid:uid]) {
              // 创建失败
              return NO;
         }
    }
   // 2、检测表格是否需要更新,需要则更新,不需要则不更新
   if ([self isUpdateTable:cls uid:uid]) {
        // 更新表格
        [self updateTable:cls uid:uid];
    }
    // 3、判断记录是否存在,按照主键的值查询,如果能查询到,那么久更新数据,如果查询不到,就把这条数据插入
    // 获取表名
    NSString *tableName = [JKSqliteModel tableName:cls];
    // 判断模型里面是否有主键
    if (![cls respondsToSelector:@selector(primaryKey)]) {
         NSLog(@"请设置模型里面的主键,遵守协议,实现+(NSString *)primaryKey;,d从而得到主键信息");
         return NO;
    }
    // 拿到主键
    NSString *primaryKey = [cls primaryKey];
    // 模型里面主键的值
    id primaryKeyValue = [model valueForKeyPath:primaryKey];
    // 创建sql语句
    NSString *checkPrimaryKeySql = [NSString stringWithFormat:@"select * from %@ where %@ = %@",tableName,primaryKey,primaryKeyValue];
    // 进行查询
    // 获取表中所有的字段(下面的方法获取的是字典,我们取其键)
    NSArray *columnNames = [JKSqliteModel classIvarNameTypeDictionary:cls].allKeys;
    // 获取模型里面所有的值数组
    NSMutableArray *columnNameValues = [NSMutableArray array];
    for (NSString *columnName in columnNames) {
        id columnNameValue = [model valueForKeyPath:columnName];
        [columnNameValues addObject:columnNameValue];
    }
    // 把字段和值拼接生成  字段 = 值   字符的数组
    NSInteger count = columnNames.count;
    NSMutableArray *setValueArray = [NSMutableArray array];
    for (int i = 0; i<count; i++) {
         NSString *name = columnNames[I];
         id value = columnNameValues[I];
         NSString *setStr = [NSString stringWithFormat:@"%@ = '%@'",name,value];
         [setValueArray addObject:setStr];
     }
     NSString *execSql = @"";
     if ([JKSqliteDatabase querySql:checkPrimaryKeySql witUid:uid].count > 0) {
          // update 表名 set 字段1=值 字段2=值.... where 主键名 = 对应的主键值;"
          // 查询的结果大于0说明表中有这条数据,进行数据更新
          // 获取 更新的 sql 语句
          execSql = [NSString stringWithFormat:@"update %@ set %@ where %@ = %@;",tableName,[setValueArray componentsJoinedByString:@","],primaryKey,primaryKeyValue];
     }else{
          // 不存在数据,进行记录的插入操作
          // 提示这里 insert into %@(%@) values('%@');,其中的value 要是: 'value1','value2','value2'这样的格式
          execSql = [NSString stringWithFormat:@"insert into %@(%@) values('%@');",tableName,[columnNames componentsJoinedByString:@","],[columnNameValues componentsJoinedByString:@"','"]];
      }
   return [JKSqliteDatabase deal:execSql witUid:uid];
}


六、删除模型



  • 6.1、删除整个模型,也是删除对应用户数据库中的一个表


/**
   删除模型,也是删除模型中的全部数据,可以说是删除整个表
 */
+(BOOL)deleteModel:(id)model uid:(NSString *)uid{
   Class cls = [model class];
   // 获取表名
   NSString *tableName = [JKSqliteModel tableName:cls];
   if (![JKSqliteTableTool isTableExists:cls uid:uid]) {
       // 表不存在默认删除成功
       return YES;
   }
   // 组建删除表的语句
   NSString *deleteSql = [NSString stringWithFormat:@"drop table %@;",tableName];
   return [JKSqliteDatabase deal:deleteSql witUid:uid];
}
  • 6.2、根据主键删除模型中的某一条数据


/**
  删除模型里面的一条记录
*/
+(BOOL)deleteRecordingModel:(id)model uid:(NSString *)uid{
   Class cls = [model class];
   // 判断模型里面是否有主键
   if (![cls respondsToSelector:@selector(primaryKey)]) {
       NSLog(@"请设置模型里面的主键,遵守协议,实现+(NSString *)primaryKey;,d从而得到主键信息");
       return NO;
   }
   // 拿到主键
   NSString *primaryKey = [cls primaryKey];
   // 模型里面主键的值
   id primaryKeyValue = [model valueForKeyPath:primaryKey];
   // 获取表名
   NSString *tableName = [JKSqliteModel tableName:cls];
   NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ = %@;",tableName,primaryKey,primaryKeyValue];
   return [JKSqliteDatabase deal:deleteSql witUid:uid];
}
  • 6.3、根据用户的条件删除表中的记录(根据条件删除)


+(BOOL)deleteModel:(id)model whereStr:(NSString *)condition uid:(NSString *)uid{
    Class cls = [model class];
    // 获取表名
    NSString *tableName = [JKSqliteModel tableName:cls];
    // 条件小于0直接返回
    if (!(condition.length > 0)) {
        return NO;
    }
    // 组建删除表的语句
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@;",tableName,condition];
    return [JKSqliteDatabase deal:deleteSql witUid:uid];
}

提示:在使用这个条件的方法,要求开发者会 sql 语句,要求高一些


七、查询模型



  • 7.1、查询模型中所有的数据


/** 查询模型中所有的数据 */
+(NSArray *)queryAllDataModel:(Class)cls uid:(NSString *)uid{
     // 1.查询前序
     // 获取表名
     NSString *tableName = [JKSqliteModel tableName:cls];
     // 组合查询语句
     NSString *querySql = [NSString stringWithFormat:@"select * from %@",tableName];
     // 2.执行查询 key value
     // 模型的属性名称 和 属性值
     NSArray <NSDictionary *>*results = [JKSqliteDatabase querySql:querySql witUid:uid];
     // 3.处理查询结果集 -> 模型数组
     return [self parseResults:results withClass:cls];
}
  • 7.2、 根据条件来查询模型里面的部分数据


+(BOOL)queryDataModel:(Class)cls whereStr:(NSString *)condition uid:(NSString *)uid{
   // 1.查询前序
   // 获取表名
   NSString *tableName = [JKSqliteModel tableName:cls];
   // 组合查询语句
   NSString *querySql = [NSString stringWithFormat:@"select * from %@ where %@;",tableName,condition];
   // 2.执行查询 key value
   // 模型的属性名称 和 属性值
   NSArray <NSDictionary *>*results = [JKSqliteDatabase querySql:querySql witUid:uid];
   // 3.处理查询结果集 -> 模型数组
   return [self parseResults:results withClass:cls];
}


八、模型中-字典/数组属性处理



  • 8.1、分析:对于字典和数组存储数据库,我们组要把它们先转为 NSData,再转为NSStrinig;在取值的时候,我们进行反序列化,根据模型里面字段的类型,把数据库中的数组或者字典的字符串值转化为NSData,再反序列化为对应的类型,从而使用 KVC 赋值给对应的key
  • 8.2、字典和数组存储数据库的核心代码(完整代码在JKSqliteModelTool里面的+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid方法中)


// 获取表中所有的字段(下面的方法获取的是字典,我们取其键)
NSArray *columnNames = [JKSqliteModel classIvarNameTypeDictionary:cls].allKeys;
// 获取模型里面所有的值数组
NSMutableArray *columnNameValues = [NSMutableArray array];
for (NSString *columnName in columnNames) {
     id columnNameValue = [model valueForKeyPath:columnName];
     // 判断类型是不是数组或者字典
     if ([columnNameValue isKindOfClass:[NSArray class]] || [columnNameValue isKindOfClass:[NSDictionary class]]) {
          // 在这里我们把数组或者字典处理成一个字符串,才能正确的保存到数据库里面去
          // 字典/数组 -> NSData ->NSString
          NSData *data = [NSJSONSerialization dataWithJSONObject:columnNameValue options:NSJSONWritingPrettyPrinted error:nil];
          columnNameValue = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
      }
      [columnNameValues addObject:columnNameValue];
}

注意:上面在可变与不可变的处理,可变的数组或者字典是继承于不可变的


  • 8.3、字典和数组从数据库读取的核心代码(具体的代码请看JKSqliteModelTool里面的+ (NSArray *)parseResults:(NSArray <NSDictionary *>*)results withClass:(Class)cls方法)


NSString *type = nameTypeDic[key];
//
id resultValue = obj;
if ([type isEqualToString:@"NSArray"] || [type isEqualToString:@"NSDictionary"]) {
      // 字符串 -> NSData -> 相应的类型
      NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
      /**
         NSJSONReadingMutableContainers = (1UL << 0), 可变的
         NSJSONReadingMutableLeaves = (1UL << 1), 可变的的类型里面还有可变的
          NSJSONReadingAllowFragments =
          kNilOptions 不可变
       */
       resultValue = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
}else if ([type isEqualToString:@"NSMutableArray"] || [type isEqualToString:@"NSMutableDictionary"]){
        // 字符串 -> NSData -> 相应的类型
        NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
        resultValue = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
}
[model setValue:resultValue forKey:key];

注意:上面在可变与不可变的处理上


9、存在问题-优化方案



  • 9.1、存在的问题一:无法创建复杂的表格, 比如添加约束等行为,如下的创建表,很多的字段,后面都是有一定的约束以及一些默认的值


create table students(
     id int unsigned primary key auto_increment not null,
     name varchar(20) default '',
     age tinyint unsigned default 0,
     height decimal(5,2),
     gender enum('男','女','人妖','保密') default "保密",
     cls_id int unsigned default 0
);

解决办法:用协议解决,告诉我们每个字段需要加什么约束,我们在创建表或者更新字段的时候 拼接在相应的字段后面


  • 9.2、存在的问题二:无法进行复杂的查询, 比如多表联查


解决办法:暴漏完整的sql语句来执行


10、上面所有步骤组合起来的JKSqliteKit的使用



  • 10.1、创建项目,导入 libsqlite3.0.tbd,步骤和 1.1 一样
  • 10.2、主要的类
  • JKSqliteDatabase : 数据库的操作
  • JKSqliteModel :模型的操作
  • JKSqliteModelTool : 操作模型的类
  • JKSqliteTableTool : 有关表的操作
  • JKSqliteProtocol :存放协议的内容
  • 10.3、具体使用
  • <1>、创建一个 Person 类继承于 NSObject,设置如下四个属性


#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
/** 人的ID */
@property(nonatomic,assign) int personID;
/** 人的名字 */
@property(nonatomic,strong) NSString *personName;
/** 人的年龄 */
@property(nonatomic,strong) NSString *personAge;
/** 人的身高 */
@property(nonatomic,strong) NSString *personHeight;
/** 人的爱好 */
@property(nonatomic,strong) NSArray *personLikes;
@end
NS_ASSUME_NONNULL_END
  • <2>、导入协议:#import "JKSqliteProtocol.h",设置personID(人的ID)为主键,主键是必须设置的,在协议里面我们设置了@required


// 导入协议
#import "JKSqliteProtocol.h"
// 设置主键
+(NSString *)primaryKey{
   return @"personID";
}
  • <3>、找个控制器,创建一个 Person 模型,模型属性赋值,存入数据库,我们采用的用户机制,不同的用户登录app,对应不同的数据库,格式是: jk_用户的ID.sqlite,未登录是:jk_common.sqlite,存在于 沙盒的/Library/Caches


Person *person = [[Person alloc]init];
person.personID = 2;
person.personName = @"王小二";
person.personAge = 29;
person.personHeight = 178;
person. personLikes =@["篮球",@"足球"];
BOOL result = [JKSqliteModelTool saveOrUpdateModel:person uid:@"1"];
if(result){
      // 保存成功
}else{
      // 保存失败
}


image.png

  • <4>、取出模型使用


NSArray *resultArray = [JKSqliteModelTool queryAllDataModel:NSClassFromString(@"Person") uid:@"1"];
NSLog(@"resultArray=%@",resultArray);
for (Person *person in resultArray) {
    NSLog(@"personID =%d",person.personID);
    NSLog(@"personName=%@",person.personName);
    NSLog(@"personAge=%d",person.personAge);
    NSLog(@"personHeight=%lf",person.personHeight);
    NSLog(@"personLikes=%@",person.personLikes);
}
  • <5>、把Person模型中表中字段 personName 改为 name
  • Peson.h 修改 personNamename


/** 人的名字 */
// @property(nonatomic,strong) NSString *personName;
// 改后的名字
@property(nonatomic,strong) NSString *name;
  • Peson.m 里面实现改表中名字的协议


+(NSDictionary *)updateFieldNewNameReplaceOldName{
      return @{@"name":@"personName"};
}

提示:字典的key是新字段名,value是旧的字段名

  • 执行替换字段的方法


BOOL result = [JKSqliteModelTool updateTable:[Person class] uid:@"1"];
if(result){
    NSLog(@"修改成功");
}else{
    NSLog(@"修改失败");
}


image.png



  • <6>、删除Person模型(也可以说是删除这个Person模型的表)


Person *person = [[Person alloc]init];
BOOL result = [JKSqliteModelTool deleteModel:person uid:@"1"];
if(result){
     NSLog(@"删除模型成功");
}else{
     NSLog(@"删除模型失败");
}


最后,建议看着 demo 读这篇博客,里面有很多的知识可以去学习,这篇博客仅仅是引出 Realm 做铺垫,下篇博客我们再

目录
相关文章
|
28天前
|
存储 SQL 数据库
数据库知识:了解SQLite或其他移动端数据库的使用
【10月更文挑战第22天】本文介绍了SQLite在移动应用开发中的应用,包括其优势、如何在Android中集成SQLite、基本的数据库操作(增删改查)、并发访问和事务处理等。通过示例代码,帮助开发者更好地理解和使用SQLite。此外,还提到了其他移动端数据库的选择。
31 8
|
1月前
|
Web App开发 SQL 数据库
使用 Python 解析火狐浏览器的 SQLite3 数据库
本文介绍如何使用 Python 解析火狐浏览器的 SQLite3 数据库,包括书签、历史记录和下载记录等。通过安装 Python 和 SQLite3,定位火狐数据库文件路径,编写 Python 脚本连接数据库并执行 SQL 查询,最终输出最近访问的网站历史记录。
|
1月前
|
存储 关系型数据库 数据库
轻量级数据库的利器:Python 及其内置 SQLite 简介
轻量级数据库的利器:Python 及其内置 SQLite 简介
|
1月前
|
应用服务中间件 PHP Apache
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
|
2月前
|
存储 API 数据库
QML使用Sqlite数据库存储ListModel数据
本文介绍了在QML中使用Sqlite数据库存储ListModel数据的方法,包括如何创建数据库、读取数据、动态添加和删除数据,以及如何在程序启动和退出时与数据库同步数据。
|
2月前
|
数据库 数据库管理
qt对sqlite数据库多线程的操作
本文总结了在Qt中进行SQLite数据库多线程操作时应注意的四个关键问题,包括数据库驱动加载、加锁、数据库的打开与关闭,以及QsqlQuery变量的使用。
169 1
|
1月前
|
存储 缓存 关系型数据库
sqlite 数据库 介绍
sqlite 数据库 介绍
40 0
|
3月前
|
人工智能 小程序 Java
【工具】轻松解锁SQLite数据库,一窥微信聊天记录小秘密
本文介绍了一款名为PyWxDump的开源工具,它可以获取微信账户信息、解密SQLite数据库以查看和备份聊天记录。此工具适用于已登录电脑版微信的用户,通过GitHub下载后简单几步即可操作。适合对数据恢复感兴趣的开发者,但请注意合法合规使用并尊重隐私。
525 2
【工具】轻松解锁SQLite数据库,一窥微信聊天记录小秘密
|
2月前
|
JSON NoSQL 数据库
和SQLite数据库对应的NoSQL数据库:TinyDB的详细使用(python3经典编程案例)
该文章详细介绍了TinyDB这一轻量级NoSQL数据库的使用方法,包括如何在Python3环境中安装、创建数据库、插入数据、查询、更新以及删除记录等操作,并提供了多个编程案例。
124 0
|
3月前
|
SQL 存储 小程序
【教程】navicat配合HTTP通道远程连接SQLite数据库
本文介绍了如何通过 Navicat Premium 工具配合 n_tunnel_sqlite.php 和 HTTP 通道远程连接服务器上的 SQLite 数据库。SQLite 是一种自给自足的、无服务器的 SQL 数据库引擎,由于其端口未对外开放,直接使用 Navicat 进行远程连接不可行。文章详细记录了使用 HTTP 通道实现远程连接的过程,包括定位本地 `ntunnel_sqlite.php` 文件,将其上传至服务器,并通过 Navicat 配置 HTTP 通道连接 SQLite 数据库的具体步骤。
179 0
【教程】navicat配合HTTP通道远程连接SQLite数据库
下一篇
无影云桌面