`

改造SQLitePlugin插件,用FMDB统一管理

 
阅读更多

接上篇博客:

hybrid应用的database locked问题

我们的是hybrid应用,基于cordova。做第一个版本的时候没经验,原生的部分用FMDB访问数据库,WEB的部分就直接找了一个SQLitePlugin用。早期的时候,原生代码和js访问数据库都是错开的,所以没有发生问题。但是到了现在,有些场景需要2边一起访问数据库,由于sqlite不支持并发写,就产生了database locked问题

其实回头看,如果在首版本就基于FMDB自己写一个cordova插件提供给js调用是很容易的,但是到了现在再改造就麻烦了很多,因为业务代码已经大量调用了SQLitePlugin的js接口,所以SQLitePlugin的js部分肯定是不能动了,不然业务代码就都得改。所以最后决定采用的方案,就是把SQLitePlugin的原生部分,重新借助FMDB实现一次。这样应用的原生代码,和cordova插件,都是用FMDatabaseQueue来管理,就不会发生锁库的现象了

改造的过程难度不大,主要就是2大块:

1、把SQLitePlugin里操作数据库的代码,比如sqlite3_step之类的,用FMDB提供的API替换掉

2、通过DEBUG,弄清楚js部分和原生代码部分的参数和返回值,然后适配接口,保证正确处理js传来的参数,并返回和原来的实现一样的返回值

把所有代码读了一遍,发现其实核心部分是这个方法:

-(CDVPluginResult*) executeSqlWithDict: (NSMutableDictionary*)options

options就是js传过来的参数,里面有sql,params,query,qid这4个key,所以接下来我们调用FMDB API所需要的参数,也是从其中取出来。而这个方法最后的返回值,必须包含qid,type,result,error,具体来说,qid是原样返回,type可能是success或error,result则必须包含rows,也就是select查询的结果(其实还有rowAffected和其他一些key,但是检查了发现没有用,所以新的实现就忽略了这些key)

上述的参数和返回值搞清楚以后,剩下的部分就是重新实现。SQLitePlugin原来的代码有1000行左右,所做的也无外乎调用sqlite3的api,还有处理类型转换,参数绑定等常规动作,这些事情在FMDB里都已经做过了,所以借助FMDB重新实现是非常简单的。改造后的代码只有200行不到,核心也是这个方法:

-(CDVPluginResult*) executeSqlWithDict: (NSMutableDictionary*)options
{
    NSString *sql = [options objectForKey:@"sql"];
    NSArray *params = [options objectForKey:@"params"];
    
    NSMutableArray *resultRows = [NSMutableArray array];// 查询结果集
    __block NSDictionary *error = nil;
    
    [dbHelper doOperation:^(FMDatabase *db){
        
        if([[sql lowercaseString] hasPrefix:@"select"]){
            
            FMResultSet *rs = [db executeQuery:sql withArgumentsInArray:params];
            
            if(!rs){
                error = @{@"code":[NSNumber numberWithInt:[db lastErrorCode]], @"message": [db lastErrorMessage]};
            }else{
                while([rs next]){
                    [resultRows addObject:[rs resultDictionary]];
                }
                [rs close];
            }
        }else{
            
            BOOL result = [db executeUpdate:sql withArgumentsInArray:params];
            if(!result){
                error = @{@"code":[NSNumber numberWithInt:[db lastErrorCode]], @"message": [db lastErrorMessage]};
            }
        }
    }];
    
    if(error){
        return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:error];
    }
    
    NSDictionary *cdvResult = @{@"rows": resultRows};
    return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:cdvResult];
}

只要熟悉FMDB的API,上面的代码都是很直接的,没有什么需要特别说明的。

另外,这个plugin持有一个dbHelper的实例变量:

{
    YLSDatabaseHelper *dbHelper;
}

-(CDVPlugin*) initWithWebView:(UIWebView*)theWebView
{
    self = (SQLitePlugin*)[super initWithWebView:theWebView];
    if (self) {
        dbHelper = [YLSDatabaseHelper sharedInstance];
    }
    return self;
}

这个YLSDatabaseHelper是个单例,原生的代码以及这个插件,都通过这个唯一入口访问数据库,因此保证了不会并发写(FMDatabaseQueue的内部机制)。如果这个dbHelper不是单例,而是有多个实例,其实是无法避免database locked的

@implementation YLSDatabaseHelper

{
    FMDatabaseQueue* queue;
}

-(id) init
{
    self = [super init];
    if(self){
        NSString *dbFilePath = [YLSGlobalUtils getDatabaseFilePath];
        queue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];
    }
    return self;
}

+(YLSDatabaseHelper*) sharedInstance
{
    static dispatch_once_t pred = 0;
    __strong static id _sharedObject = nil;
    dispatch_once(&pred, ^{
        _sharedObject = [[self alloc] init];
    });
    return _sharedObject;
}

+(void) refreshDatabaseFile
{
    YLSDatabaseHelper *instance = [self sharedInstance];
    [instance doRefresh];
}

-(void) doRefresh
{
    NSString *dbFilePath = [YLSGlobalUtils getDatabaseFilePath];
    queue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];
}

-(void) doOperation:(void(^)(FMDatabase*))block
{
    [queue inDatabase:^(FMDatabase *db){
        block(db);
    }];
}

@end

这样改造之后,对js部分完全没有影响,WEB里的业务代码一点都不需要修改。但是毕竟是改造,其实如果在首版本就能意识到这个问题,可以直接这样写一个插件,不需要引入SQLitePlugin,然后插件的js部分也可以简单很多
分享到:
评论

相关推荐

    FMDB多表管理

    **FMDB多表管理**是iOS开发中数据库操作的一个实用示例,它利用了FMDB库来高效地管理和操作项目中的多个数据表。FMDB是一个Objective-C封装的SQLite数据库管理库,提供了简单易用的API,使得在iOS应用中进行SQL查询...

    ios 数据库 (FMDB使用)

    本篇将详细介绍如何使用 FMDB 在 iOS 应用中实现数据库的增删改查,并通过单例模式来高效管理数据库操作。 首先,我们需要了解 FMDB 的基本概念。FMDB 是基于 SQLite 的,因此它支持 SQL 语句执行,包括 SELECT、...

    使用fmdb的一个ios demo

    而`FMDB`是Objective-C编写的SQLite管理库,它为iOS开发者提供了一个简单易用的接口来操作SQLite数据库。本文将深入探讨`FMDB`的使用,以及如何通过`SmartFMDB`这个示例项目进行学习。 **1. FMDB介绍** `FMDB`由...

    FMDB 简单使用

    FMDB是iOS和macOS平台上一个非常流行的SQLite数据库管理库,它是用Objective-C编写的,提供了简单而强大的接口来操作SQLite数据库。在这个标题为“FMDB简单使用”的主题中,我们将深入探讨如何在你的Objective-C项目...

    数据库第三方FMDB

    FMDB是iOS开发中常用的第三方数据库管理库,它是基于SQLite的一个Objective-C封装,极大地简化了在iOS应用中使用SQLite数据库的操作。在这个项目中,你只需将FMDB文件夹直接拖入你的工程,然后引入相关头文件,即可...

    使用FMDB写的demo

    FMDB是一款非常流行的iOS和macOS平台上的SQLite数据库管理库,它是由GitHub上的SSSQLite项目发展而来的。SQLite是一款轻量级的、嵌入式的、关系型数据库,广泛应用于移动应用中,因为它不需要独立的服务器进程,并且...

    iosFMDB开发的通讯录

    本项目“iosFMDB开发的通讯录”就是利用FMDB这一强大的SQLite数据库管理库,实现了一个功能丰富的手机通讯录应用。FMDB是Objective-C编写的SQLite封装库,它使得在iOS平台上操作SQLite数据库变得简单易行。 首先,...

    FMDB库和配置

    FMDB库是iOS平台上一个非常流行的SQLite数据库管理工具,它是由GitHub上的Zee Zide开源的。这个库为Objective-C开发者提供了一套简单易用的API,使得在iOS应用中操作SQLite数据库变得轻而易举。FMDB不仅封装了SQLite...

    fmdb的封装

    FMDB是iOS开发中常用的一个SQLite数据库管理库,它是一个Objective-C封装的SQLite库,提供了简单易用的接口来操作数据库。在这个“fmdb的封装”项目中,开发者已经对FMDB进行了更进一步的封装,使得数据库的存储、...

    FMDB数据库

    FMDB是iOS开发中广泛使用的SQLite数据库管理库,它是一个Objective-C封装的SQLite库,提供了简单易用的接口,使得开发者能够轻松地进行数据存储、查询、更新和删除操作。FMDB不仅支持基本的SQL语句执行,还包含了...

    iOS开发中使用FMDB来使程序连接SQLite数据库

    而FMDB则是iOS平台上一个优秀的SQLite数据库框架,它为开发者提供了一种更面向对象的方式来操作SQLite,使得数据库的使用变得更加简单和高效。以下是关于FMDB在iOS开发中使用SQLite数据库的详细说明: 1. **什么是...

    使用FMDB保存聊天记录

    使用FMDB保存聊天记录到本地Documents的工具类,可以参考看看

    ios-FMDB简单使用.zip

    FMDB是一个Objective-C封装的SQLite数据库管理库,由GitHub上的ccgus团队开发。它为iOS开发者提供了一种简单、直观的方式来执行SQL语句,处理SQLite数据库,实现了数据持久化。在这个“ios-FMDB简单使用.zip”压缩包...

    ios sqlite封装FMDB

    在iOS开发中,SQLite是一个广泛使用的轻量级关系型数据库,它允许开发者在应用程序中存储、管理和检索数据。而FMDB是Objective-C的一个SQLite库,它为iOS开发者提供了一个易于使用的接口来操作SQLite数据库,极大地...

    Swift基础之FMDB的使用Demo

    由于FMDB是用Objective-C编写的,所以在Swift项目中使用需要桥接头文件。确保你已经创建了桥接头文件(ProjectName-Bridging-Header.h),然后在其中导入FMDB库: ```swift #import <FMDB/FMDB.h> ``` 接下来,...

    fmdb增删改查

    FMDB是iOS和macOS平台上一个非常流行的SQLite数据库管理库,它是用Objective-C编写的,提供了简单易用的API来处理SQLite数据库的各种操作,包括增、删、改、查(CRUD)等基本功能。在iOS应用开发中,FMDB通常用于...

    IOS_fmdb.zip

    FMDB是iOS平台上的一个流行的第三方数据库管理库,它为SQLite提供了Objective-C的封装,使得开发者可以更方便、更直观地进行数据库操作。本篇文章将深入探讨FMDB的核心功能、使用方法以及其在iOS开发中的实际应用。 ...

    fmdb通讯录

    通过学习和使用这个`fmdb通讯录`项目,开发者不仅可以掌握如何利用`FMDB`管理SQLite数据库,还能了解到如何在iOS应用中高效地处理通讯录数据,以及如何通过`CocoaPods`来管理第三方库。这对于开发涉及大量数据操作的...

    fmdb-master_fmdb的操作方法_

    FMDB是iOS和macOS平台上一个非常流行的SQLite数据库管理库,它是用Objective-C编写的,为开发者提供了简单、直观的接口来操作SQLite数据库。在这个"fmdb-master"压缩包中,包含了FMDB库的源代码和其他相关文件,使得...

    多线程操作数据库(使用FMDB)

    演示了使用FMDB通过多线程来读和写数据库操作。现在ios里使用的数据库一般都是Sqlite,但是使用Sqlite有个不太好的地方就是在多线程的时候,会出现问题,sqlite只能打开一个读或者写连结。这样的话多线程就会碰到...

Global site tag (gtag.js) - Google Analytics