Core Data版本迁移基础

通常,在使用Core Data的iOS App上,不同版本上的数据模型变更引发的数据迁移都是由Core Data来负责完成的。
这种数据迁移模式称为Lightweight Migration(可能对于开发人员来说是lightweight),开发人员只要在添加Persistent Store时设置好对应选项,其它的就交付给Core Data来做了:

从命名上可以看出这两个选项分别代表:自动迁移Persistent Store,以及自动创建Mapping Model。

自动迁移Persistent Store很好理解,就是将数据从一个物理文件迁移到另一个物理文件,通常是因为物理文件结构发生了变化。
自动创建Mapping Model是为迁移Persistent Store服务的,所以当自动迁移Persistent Store选项NSMigratePersistentStoreAutomaticallyOption为@(YES)、且找不到Mapping Model时,coordinator会尝试创建一份。
其它初始化场景可以参考Initiating the Migration Process。

既然是尝试创建,便有成功和失败的不同结果。只有当数据模型的变更属于某些基本变化时,才能够成功地自动创建出一份Mapping Model,比如:新增一个字段;删除一个字段;必填字段转换成可选字段;可选字段转换成必填字段,同时提供了默认值等等。

因为可能创建Mapping Model失败,所以考虑容错性的话,可以事先判断下能否成功推断出一份Mapping Model:

利用如上类方法,如果无法创建一份Mapping Model,则会返回nil,并带有具体原因。

以上都建立在Core Data能够自动找到sourceModel和destinationModel的基础上,如果无法找到对应的两份Model,则需要开发人员手工创建NSMigrationManager来进行数据迁移(可以参考Use a Migration Manager if Models Cannot Be Found Automatically)。

版本迁移过程

那么,数据迁移的过程是如何进行的?

首先,发生数据迁移需要三个基本条件:可以打开既有persistent store的sourceModel,新的数据模型destinationModel,以及这两者之间的映射关系Mapping Model。

利用这三样,当调用如下代码时(addPersistentStore):

Core Data创建了两个stack(分别为source stack和destination stack,可以参考Core Data stack),然后遍历Mapping Model里每个entity的映射关系,做以下三件事情:
     1. 基于source stack,Core Data先获取现有数据,然后在destination stack里创建当前entity的实例,只填充属性,不建立关系;
     2. 重新创建entity之间的关系;
     3. 验证数据的完整性和一致性,然后保存。

考虑到第二步是重新建立entity之间的关系,那么应该是在第一步就把所有entity的对象都创建好了,并且保留在内存中,为第二步服务(事实上也是如此)。

完成第二步后,所有数据还是维持在内存中(可能还有两份,因为有两个stack),在完成数据验证后才真正保存。

这样的话,会容易导致内存占用过多,因为Core Data在这个迁移过程中也没有一种机制清理响应的context。所以在数据量较多时,App可能会遇到在数据迁移过程因为内存紧张而被系统干掉。
针对这种情况,我们可以自定义迁移过程。

自定义数据迁移(解决内存问题)

自定义数据迁移的过程通畅分为三步:
第一步是判断是否需要进行数据迁移:

第二步是创建一个Migration Manager对象:

第三步是真正发生数据迁移:

上面三幅图所展示的代码在内存使用量上跟lightweight migration也没什么区别,无法解决内存峰值过高的问题。

虽然Core Data专家Marcus S. Zarra比较倾向坚持使用lightweight migration,不过对于上述内存占用过多的问题,Apple官方推荐使用Multiple Passes来解决。

关于Multiple Passes,官方文档的说明很简明扼要,如有需要,可以参考Stackoverflow上的这么一篇帖子。

用我的话往简单里说就是对数据模型进行划分,把一份Mapping Model拆分成多份,然后分成多次迁移,从而降低内存峰值。这需要对数据库进行全盘的考虑(甚至可能需要变更部分设计),然后通过合理的划分把相关联的Entity放在一份Mapping Model里面(因为要建立关联)。

新的问题

采用上述方案来解决数据迁移过程中内存峰值的问题,我们仍然需要关注迁移所耗费的时间、内存,从而能够在数据上验证方案的有效性,并且在用户交互方面进行一些必要的更改(总不能让用户傻傻地在那边等数据迁移吧)。

虽然可以解决内存峰值的问题,但也引进了其它问题。

1. 需要对数据模型进行划分(以及变更),存在一定的工作量和风险;
2. 需要手工建立多份Mapping Model;
3. 需要手工编写Multiple Passes迁移代码;
4. 需要在每个版本变迁中都再次创建新的Mapping Model,且在跨版本迁移过程存在着其它问题;
5. 数据模型版本多起来,就面临着跨版本迁移的问题,是要为每个历史版本创建到最新模型的Mapping Model,还是只维护最近两个版本的Mapping Model(更早的版本通过相邻版本的Mapping Model依次迁移过来,比较耗时)?
6. 对数据模型重新划分后,无关的Entity简单变更也会引起整个store和model的不兼容,需要迁移,那么是否考虑分库?
7. 这么大的动作服务的用户数是很少的(只有少数用户会遇到,或者是很少),但却是比较资深的(因为消息记录多),疼。。。
8. 这无法解决单个Entity数据量过大的问题,针对这种场景,只能自己手工编码进行小批量的数据迁移;

Core Data 版本数据迁移的更多相关文章

  1. iOS开发——数据持久化Swift篇&使用Core Data进行数据持久化存储

    使用Core Data进行数据持久化存储   一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成 ...

  2. Core Data存储数据出错(This NSPersistentStoreCoordinator has no persistent stores (unknown))

    Core Data存储数据的时候崩溃,崩溃信息: reason: 'This NSPersistentStoreCoordinator has no persistent stores (unknow ...

  3. HBase跨版本数据迁移总结

    某客户大数据测试场景为:Solr类似画像的数据查出用户标签--通过这些标签在HBase查询详细信息.以上测试功能以及性能. 其中HBase的数据量为500G,Solr约5T.数据均需要从对方的集群人工 ...

  4. Entity Framework Core中的数据迁移命令

    使用程序包管理控制台输入命令. 数据迁移命令: Add-Migration  对比当前数据库和模型的差异,生成相应的代码,使数据库和模型匹配的. Remove-Migration 删除上次的迁移 Sc ...

  5. Swift - 使用Core Data进行数据持久化存储

    一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成数据,也能够将保存在数据库中的数据还原成对象. ...

  6. ASP.NET Core ef启用数据迁移

    创建一个项目 通过Nuget获取EF Core相关的扩展包 appsettings.json 建立数据库连接串 创建数据库上下文EntityDbContext类,用于实体类映射数据库表 使用包管理器控 ...

  7. Core Data 迁移与版本管理

    原文  http://chun.tips/blog/2014/11/28/core-data-ban-ben-qian-yi-jing-yan-zong-jie/ 主题 Core DataiOS开发 ...

  8. iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

                   在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...

  9. iphone数据存储之-- Core Data的使用(一)

    http://www.cnblogs.com/xiaodao/archive/2012/10/08/2715477.html 一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终 ...

随机推荐

  1. luigi学习3-使用luigid

    --local-scheduler的方式只适用于开发调试阶段,当你真正要把程序部署到一个产品时,我们推荐使用luigid服务. 使用luigid服务不但能提供锁服务(防止一个任务被多个进程重复执行), ...

  2. 如何批量转换 WordPress 文章分类

    可能建博之初,分类设置过于详细,后来想重新整理并删除一些分类项目,比如删除分类A,并将其中的所有文章划归到分类B中,手动修改文章的分类过于麻烦,有木有什么方法可以批量移动文章到另一个分类中呢? 网上闲 ...

  3. Oracle自用脚本(持续更新)

    --查询Oracle正在执行的sql语句及执行该语句的用户 SELECT b.sid oracleID, b.username 登录Oracle用户名, b.serial#, spid 操作系统ID, ...

  4. 10-排序5 PAT Judge

    用了冒泡和插入排序 果然没有什么本质区别..都是运行超时 用库函数sort也超时 The ranklist of PAT is generated from the status list, whic ...

  5. 第三章 管理程序流(In .net4.5) 之 实现程序流

    1. 概述 本章内容包括 布尔表达式.流控制方式.集合遍历 以及 流跳转. 2. 主要内容 *由于该章内容比较基础,日常用的也很多,故对一些常用的基础内容不再赘述. 2.1 使用布尔表达式 熟悉下列比 ...

  6. EmguCV学习——简单使用

    关于EmguCV我就不多说了,是对应于OpenCV的一套net库. 公司是视觉方面的业务,我又不会c++(好想会啊,正在学习中).由于各种需求,自己觉得对c++不是特别感冒,所以选用了net下的ope ...

  7. Html5 Canvas一个简单的画笔例子

    相比了下Qt quick的canvas和HTML5的canvas,发现HTML5 Canvas在同样绘制绘制操作下性能比Qt的canvas强很多,附上一个HTML5 canvas画笔一例子 var D ...

  8. 小心C语言的定义与声明

    小心C语言的定义与声明 转自360博客 注:为便于说明问题,文中提及的变量和函数都被简化. 一.起源 DBProxy在测试过程中,发现对其执行某步管理操作后,程序有时会崩溃,但不是每次都出现. 二.G ...

  9. vim代码补全-spf13,YouCompleteMe

    vim代码补全 现在的图形界面的IDE(Integrated Development Environment)一般具有语法高亮,语法检查,自动补全功能,大大提高了编程的效率. vim作为文本编辑器其强 ...

  10. 精简配置plsql developer连接oracle

    DB:11.2.0.3.0 OS:oracle-linux 5.7 公司堡垒机为了安全重新规划,各个组只能访问各个组的堡垒机磁盘空间,因此无法访问线上oracle组的磁盘空间,导致plsql deve ...