对数据库执行大量读/写操作的方法

Posted

技术标签:

【中文标题】对数据库执行大量读/写操作的方法【英文标题】:method for performing lot of read/write operations on a database 【发布时间】:2012-04-16 15:55:02 【问题描述】:

我正在开发一个 iPad 应用程序,我必须在其中对数据库执行大量读/写操作(我必须根据点击将视图上的点击存储在数据库中,然后执行一些操作)。我对在这种情况下如何进行感到困惑。我应该只创建一个 SQLite 数据库并执行读/写(这会减慢应用程序的响应时间吗??)还是有其他一些技术(我听说过核心数据,但不确定这是否适用于我的情况) . 请帮帮我

谢谢

阿吉特

【问题讨论】:

【参考方案1】:

如果您只是按顺序保存它们,然后以相同的顺序读回它们,那么常规文件可能是最好的。但是,如果您要执行其他任何操作,请使用 CoreData。它不仅仅是一个关系数据库。它允许持久对象图。此外,如果您使用 UIManagedDocument 或您自己的父/子 NSManagedObjectContext 安排,您甚至不会看到数据库命中,因为这一切都发生在后台线程中。

继续,测试一下。覆盖开始/移动/结束触摸,并在每次触摸时将对象放入数据库。如果您按照我的描述进行操作,您甚至不会注意到数据库命中。

假设模型中有两个实体,MyTouchEvent 和 MyTouch,其中 MyTouchEvent 与 MyTouch 是一对多的关系。

// Call this from touchesBegan, touchesMoved, and touchesEnded...
- (void) saveTouches:(NSSet*)touches kind:(NSString*)kind

    NSManagedObjectContext *moc = self.document.managedObjectContext;
    MyTouchEvent *myTouchEvent = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouchEvent" inManagedObjectContext:moc];
    myTouchEvent.kind = kind;
    for (UITouch *touch in touches) 
        CGPoint touchPoint = [touch locationInView:self];
        MyTouch *myTouch = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouch" inManagedObjectContext:moc];
        myTouch.x = [NSNumber numberWithFloat:touchPoint.x];
        myTouch.y = [NSNumber numberWithFloat:touchPoint.y];
        [myTouchEvent addTouchesObject:myTouch];
    
    [self.document updateChangeCount:UIDocumentChangeDone];

如果您的对象创建成本很高,您可以添加一个方法来创建私有上下文,并在其中完成所有工作,有两种选择。您可以将其作为文档的主上下文的父级,在这种情况下,您所要做的就是将代码嵌入到一个块中,然后在 MOC 上调用 save...

- (NSManagedObjectContext*)moc

    if (!_moc) 
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        _moc.parentContext = self.document.managedObjectContext;
    
    return _moc;

- (void) saveTouches:(NSSet*)touches kind:(NSString*)kind

    NSManagedObjectContext *moc = self.moc;
    [self.moc preformBlock:^
        MyTouchEvent *myTouchEvent = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouchEvent" inManagedObjectContext:moc];
        myTouchEvent.kind = kind;
        for (UITouch *touch in touches) 
            CGPoint touchPoint = [touch locationInView:self];
            MyTouch *myTouch = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouch" inManagedObjectContext:moc];
            myTouch.x = [NSNumber numberWithFloat:touchPoint.x];
            myTouch.y = [NSNumber numberWithFloat:touchPoint.y];
            [myTouchEvent addTouchesObject:myTouch];
        
        NSError *error = nil;
        [moc save:&error];
    ];

或者,您可以将其设为兄弟,在这种情况下,所有数据库都不会在主线程上运行(UIManagedDocument 的主上下文在主线程上运行,因此在上述情况下,主线程将将对象传递给执行保存的上下文)。但是,在这种情况下,您的 document.managedObjectContext 必须执行 FETCH 才能获取放入数据库的任何内容。但是,它在存储过程中不会导致主线程的性能。

- (NSManagedObjectContext*)moc

    if (!_moc) 
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        _moc.parentContext = self.document.parentContext;
    
    return _moc;

现在,这些将进入数据库,但如果您的文档想要查看它们,则必须执行提取。根据您的用例选择最好的。不过,我想你会很好地处理第一个例子。

【讨论】:

【参考方案2】:

如果有很多点击,你肯定不希望将它们中的每一个单独写入数据库。或许,累积鼠标操作并将其保存在-mouseUp: 事件中会是一个不错的折衷方案。

Core Data 可以通过简化程序来提供一些帮助。它使您可以非常快速地创建对象并推迟将它们保存到持久存储中。但是如果你安装一个CFRunLoopObserver,你可以用SQLite达到同样的效果,等到没有事件,然后将一批数据写入数据库。

无论你选择什么,策略都是累积点击并分批保存。

【讨论】:

【参考方案3】:

您最好的选择是将您的操作流式传输到文件系统上的文件中。然后你可以把它留在那里,或者如果你真的需要,通过 Core Data 将它上传到 SQLite。这样做的原因是,如果你为每个偶数提交 ManagedObjectContext,事情会运行得非常慢。

使用:backingFile = [NSFileHandle fileHandleForUpdatingAtPath:eventsFilePath]; 将您的事件附加到使用 [backingFile writeData:...];

请记住,关系数据库的主要目的是“搜索”数据。如果您不打算搜索 UI 点击事件(我怀疑您会这样做),那么流式传输到文件是您的最佳选择。

【讨论】:

以上是关于对数据库执行大量读/写操作的方法的主要内容,如果未能解决你的问题,请参考以下文章

进程的通信:共享存储消息传递和管道通信

多线程编程之顺序锁

核心数据和数据完整性:读操作与写操作。如何保护?

PG核心技术篇--MVCC

solr介绍

一文读懂数据库事务