Sqlite的数据本地化tips
实现数据本地化的步骤 1..设计模型 根据实际的业务需求,设计出model层。这个就不用多说了,直接上代码。 @property(strong,nonatomic)NSString *group_id;//分组Id @property(strong,nonatomic)NSString*group_name;//分组名称 @property(strong,nonatomic)NSString*groupOperator;//操作人 @property(strong,nonatomic)NSString*create_time;//创建时间 @property(strong,nonatomic)NSString*doctor_id;//医生id @property(strong,nonatomic)NSNumber*isSelected; @property(strong,nonatomic)NSNumber*sort;//序号 @property(strong,nonatomic)NSString*timestasp;//序号 2创建数据库文件 创建数据库文件一般有两种方法,一是通过数据库管理工具创建数据库文件,创建、设计表。我用的是sqlitemanger,也可以用其他的工具如火狐插件等,大同小异。 另一种方式是用代码创建sqlite文件,创建设计表。其实上边的工具就是封装了这些代码,实现了数据库的设计,免去了写数据库设计代码的过程。 这里我用的是第一种方法。 3.将创建的sqlite文件从bundle拷贝到沙盒的doument下,这里我用到了第三方库fmda。这里为了方便,把对数据库文件的操作封装到sqliteHelper文件里。这里我把sqlitHelper作为一个单列,把FMDatabase作为该单例的一个属性,可以看做是一个单例。你会问为什么要做成单例呢?(后边具体说) @property(nonatomic,retain,readonly)FMDatabase*db;//数据库 + (SqliteHelper *)sharedSqliteHelper { static SqliteHelper *sharedSqliteHelper;
@synchronized(self) { if(!sharedSqliteHelper) sharedSqliteHelper = [[SqliteHelper alloc] init]; returnsharedSqliteHelper; } }
- (id)init { self = [super init]; if (self) { //初始化数据库 if ([self initializeDb]) { db = [FMDatabase databaseWithPath:dbFilePath]; }; } return self; }
下边这段代码涉及到应用版本更新时且数据库表结构发生改变的情况,咱们后边再说。 }- (BOOL) initializeDb { NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES); NSString *documentFolderPath =[searchPaths objectAtIndex: 0]; //查看文件目录 NSLog(@"%@",documentFolderPath); dbFilePath = [documentFolderPathstringByAppendingPathComponent:@"e_doctor_db.sqlite"]; //END:code.DatabaseShoppingList.findDocumentsDirectory //START:code.DatabaseShoppingList.copyDatabaseFileToDocuments //数据库文件是否存在Documents路径先 不存在则复制,存在则核对版本 if (! [[NSFileManagerdefaultManager] fileExistsAtPath: dbFilePath]) { // didn't find db,need to copy NSString *backupDbPath =[[NSBundle mainBundle] pathForResource:@"e_doctor_db"ofType:@"sqlite"]; if (backupDbPath == nil) { // couldn't find backup db tocopy,bail return NO; } else { BOOL copiedBackupDb =[[NSFileManager defaultManager] copyItemAtPath:backupDbPath toPath:dbFilePatherror:nil]; if (! copiedBackupDb) { // copying backup db failed,bail return NO; } else { [self updateDBVersion]; } } } else { //存在则核对版本 检查是否有更新 NSString *dbverson=[selfgetCurrentDBVersion]; if ([dbversondoubleValue]!=api_ios_db_verson) { //版本号不一致 //删除数据库文件 重新复制一下数据库 if ([[NSFileManagerdefaultManager] removeItemAtPath:dbFilePath error:nil]) { //删除成功 重新复制一下数据库 NSString *backupDbPath =[[NSBundle mainBundle] pathForResource:@"e_doctor_db"ofType:@"sqlite"];
if (backupDbPath == nil) { // couldn't find backup db tocopy,bail return NO; } else { BOOL copiedBackupDb =[[NSFileManager defaultManager] copyItemAtPath:backupDbPath toPath:dbFilePatherror:nil]; if (! copiedBackupDb) { // copying backup db failed,bail return NO; } else { [self updateDBVersion]; } } } else { NSLog(@"数据库删除失败”); return NO; } } } return YES; } 3.咱们开始写dao层。 上部分截图: @interface PatientGroupService : NSObject /************************************************************ 方法名称:+ (NSArray *) getAllGroupsWithDoctorId:(NSString*)doctorId; 方法描述:获取医生对应的分组列表 参数:doctorId :医生 id 返回值:医生对应的分组列表对象的数组 ***********************************************************/ + (NSArray *)getAllGroupsWithDoctorId:(NSString *)doctorId; /************************************************************ 方法名称:+ (BOOL)addGroupWithDoctorId:(PatientGroupModel *)model; 方法描述:添加一个新分组 参数:model :分组对象 返回值:添加是否成功 yes为成功 no为失败 ***********************************************************/ + (BOOL) addGroup:(PatientGroupModel *)model; @implementation PatientService +(BOOL)addPatient:(PatientModel *)patient { BOOL result=false;
//获取数据库对象,因为所以程序都用一个数据库所以都从sqliteHelper中取用 FMDatabase *db=[SqliteHelper sharedSqliteHelper].db; NSString *sql=@"insert into t_patient(patient_id,telephone,name,sex,birthday,address,remark,message_number,message_updatetime,create_time,timestamp,group_id,doctor_id,allergic_history,status,certificate,medicare_card,socialsecurity_card)values(?,?,?)";//18 @try { //打开数据库 if ([db open]) { //执行插入语句获得执行结果 result = [db executeUpdate:sql withArgumentsInArray:@[patient.pId,patient.phoneNum,patient.name,patient.sex,patient.birthDay,patient.address,[CommonHelperisBlankString:patient.headimge_url],patient.messageNum,patient.messageUpdatetime,patient.creatTime,patient.timestamp,patient.groupId,patient.doctorId,patient.allergicHistory,patient.status,patient.certificate,patient.medicare_card,patient.socialsecurity_card]]; } } @catch (NSException *exception) { NSLog(@"添加病人出错:%@",exception); } @finally { //使用完毕之后一定要关闭数据库 [db close]; } return result; } + (NSArray *)getAllGroupsWithDoctorId:(NSString*)doctorId{ //获取数据库对象,因为所以程序都用一个数据库所以都从sqliteHelper中取用 FMDatabase *db=[SqliteHelper sharedSqliteHelper].db; NSString *sql=@"selectgroup_id,group_name,operator,sort,timestamp fromt_patient_group where doctor_id = ? order by create_time "; NSMutableArray *array=[NSMutableArray array]; @try { //打开数据库 if ([db open]) { //执行查询语句获得执行结果 FMResultSet *resultset = [db executeQuery:sqlwithArgumentsInArray:@[doctorId]]; //循环Resultset获取值 while ([resultset next]) { PatientGroupModel *model=[[PatientGroupModelalloc]init]; model.group_id=[resultset stringForColumn:@"group_id"]; model.group_name=[resultset stringForColumn:@"group_name"]; model.create_time=[resultset stringForColumn:@"create_time"]; model.groupOperator=[resultset stringForColumn:@"operator"]; model.sort=[NSNumber numberWithInt:[resultsetintForColumn:@"sort"]]; model.doctor_id=[resultset stringForColumn:@"doctor_id"]; model.isSelected = NO; model.timestasp=[resultset stringForColumn:@"timestamp"]; //将对象添加到array [array addObject:model]; } } } @catch (NSException *exception) { NSLog(@"查询病人分组出错:%@",exception); } @finally { //使用完毕之后一定要关闭数据库 [db close]; } return array; } + (BOOL) addGroup:(PatientGroupModel*)model{ BOOL result=false;
//获取数据库对象,因为所以程序都用一个数据库所以都从sqliteHelper中取用 FMDatabase *db=[SqliteHelper sharedSqliteHelper].db; NSString *sql=@"insert intot_patient_group(group_id,is_selected,timestamp)values(?,?)"; @try { //打开数据库 if ([db open]) { //执行插入语句获得执行结果 result = [db executeUpdate:sql withArgumentsInArray:@[model.group_id,model.group_name,model.create_time,model.groupOperator,model.sort,model.doctor_id,[NSNumbernumberWithBool:NO],model.timestasp]]; } } @catch (NSException *exception) { NSLog(@"添加病人分组出错:%@",exception); } @finally { //使用完毕之后一定要关闭数据库 [db close]; } return result; } }上边的代码中? 和 @[]里的参数对应,多个参数用,隔开 FMResultSet *resultset =[db executeQuery:sql withArgumentsInArray:@[]] 当然也可以用stringWithFormat拼接 NSString *l = [NSStringstringWithFormat:@"selectgroup_id,timestampfrom t_patient_group where doctor_id = %@ order by create_time",doctorId]; 上边边的执行查询改为 FMResultSet *resultset =[db executeQuery:l]; 程序中调用如下: [PatientGroupService addGroup:groupModel]; NSArray *arr = [PatientGroupServicegetAllGroupsWithDoctorId:@””]; 注1:为什么要使用单例 实际操作中你可能会出现以下的两个错误: 问题一:"is currently in use" 出现的场景是这样的,多线程操作数据库,每个线程都使用了FMDatabase实例(注意没有使用FMDatabaseQueue)。 问 题二:“database is locked"出现的场景是这样的,多线程操作数据库,每个线程各自创建了FMDatabaseQueue实例操作数据库,或者一个线程创建 FMDatabaseQueue实例来操作,而另外的线程创建了FMDatabase实例来操作。 原 因:FMDB多线程操作数据库,必须使用FMDatabaseQueue,而且必须只创建一个实例,也就是多个线程操作数据库的是同一个FMDatabaseQueue实例。首先FMDatabase是不具备线程安全的,如果两个线程中同时操作数据库,就会"iscurrently in use" ;FMDatabasequeue其实是一个调度队列(G-C-D),数据库的操作必须是顺序执行,不能两个数据库的操作同时执行,如果是两个线程各自创 建了FMDatabaseQueue的实例,线程同时执行时,就会出现相同的数据库操作同时触发,导致”database islocked“,所以必须是一个FMDatabaseQueue实例下,多个线程下同时操作,其实是在排在同一个队列中逐一操作的,没有同时操作。 注意:FMDatabaseQueue其实是在排在同一个队列中逐一操作的,并没有提高执行效率。我选用的是第一种方法,你也可以使用FMDatabaseQueue,验证下是否能够提高执行效率。 解决:有两种解决方案 1. FMDatabase 作为单例,同步进行数据库操作。 2.只创建一个FMDatabaseQueue实例,所有的FMDatabase的实例方法都在这个FMDatabaseQueue实例中执行。 这里我选用了第一种解决方法。 注2:数据库版本 随着软件的迭代,数据库结构也会发生改变,怎么样才能在小版本更新(数据库结构不变的情况下)尽量少的清空数据的数据。 定义一个全局宏db_version 在sqlite文件里建立一个配置表 这里就有了文章开头说到的数据库版本控制,仅当数据库结构发生变化时才把该sqlite文件删除,其他情况下只对数据库里的记录修改就可以了,节省了流量。 注意:数据库版本和程序的版本是不一定是相同的,仅当数据库结构发生变化时,才修改宏的值,而且必须修改宏的值,否则会使程序的数据结构错误,照成崩溃或者数据无法写入的情况。 注意3:向数据库里写数据时记得先清楚旧的记录,否则会因为主键相同插入数据库失败,导致数据不更新的情况
注4:利用时间戳来进一步节省流量(实际使用中有可能涉及到关系表,有些麻烦) 数据量较大的应用,一般都会在本地建一个小型的数据库,将服务端的一部分数据放在本地进行,以提升用户体验,但是问题来了,以朋友表为例,若数据量很大的话,上万条记录,你不能每次都把所有的数据都网络获取一遍(浪费流量,你会等待很长时间),此时你可以通过时间戳来解决数据的同步问题。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |