UDN-企业互联网技术人气社区

板块导航

浏览  : 1519
回复  : 0

[讨论交流] GYDataCenter:高性能数据库框架

[复制链接]
瞌睡虫的头像 楼主
发表于 2016-7-7 10:38:26 | 显示全部楼层 |阅读模式
  GYDataCenter是一个SQLite数据库框架,提供了一套简单易用的面向对象的数据操作接口,同时保留了SQL查询的灵活性。GYDataCenter简单易上手,相对于CoreData,GYDataCenter的学习成本更低。同时,根据自己的需求,开发者可以更方便地划分数据库,设计数据库表,数据库索引等。

  概览

  GYDataCenter具有以下特性:

  面向对象的数据操作接口

  使用SQLite的where语句做为查询条件

  自动创建及更新数据库表

  高性能cache层

  faulting机制(类似CoreData)

  自动批量写入磁盘

  使用ANALYZE优化查询

  使用方法

  1)把model类继承于GYModelObject。

  @interfaceEmployee:GYModelObject

  @property(nonatomic,assign)NSIntegeremployeeId;

  @property(nonatomic,strong)NSString*name;

  @property(nonatomic,strong)NSDate*dateOfBirth;

  @property(nonatomic,strong)Department*department;

  @end

  2)实现下面的protocol方法,指定数据库名,表名,指定哪个property做为主键(主键可以为nil),以及哪些property需要持久化。

  +(NSString*)dbName{

  return@"GYDataCenterTests";

  }

  +(NSString*)tableName{

  return@"Employee";

  }

  +(NSString*)primaryKey{

  return@"employeeId";

  }

  +(NSArray*)persistentProperties{

  staticNSArray*properties=nil;

  if(!properties){

  properties=@[

  @"employeeId",

  @"name",

  @"dateOfBirth",

  @"department"

  ];

  });

  returnproperties;

  }

  3)实现上面方法后,即可以存储,查询,更新数据。

  Employee*employee=...

  [employeesave];

  employee=[EmployeeobjectForId:@1];

  NSArray*employees=[EmployeeobjectsWhere:@"WHEREemployeeId<?ORDERBYemployeeId"

  arguments:@[@10]];

  4)这里的查询条件使用的还是SQL的where语句,这样做有两个好处:

  学习成本低。如果你已经熟悉SQL的语法,GYDataCenter可以很快上手,你无需再学习一套新的查询语法。

  保持了SQL查询的灵活性。

  实际上,跟原生SQL一样,除了where语句,你也可以直接使用orderby,limit等其它语句:

  NSArray*employees=[EmployeeobjectsWhere:@"ORDERBYemployeeId"

  arguments:nil];

  NSArray*employees=[EmployeeobjectsWhere:@"LIMIT1"

  arguments:nil];

  甚至是内嵌查询:

  NSArray*employees=[EmployeeobjectsWhere:@"WHEREdepartmentin(SELECTdepartmentIdfromdepartmentWHEREname=?)"

  arguments:@[@"HumanResource"]];

  特性

  自动创建及更新数据库表

  如上面所示,开发者只需把model继承于GYModelObject,并实现必要的protocol方法,即可以存储,查询,更新model对象了。开发者无需自己创建数据库,数据库表等,GYDataCenter会自动创建。

  并且,当一个数据库表已经存在时,如果开发者添加了新的持久化的property,GYDataCenter也会自动更新数据库表,添加相应的column定义。

  但是,GYDataCenter不能自动删除或修改已经存在的column,如果开发者因业务变更需要这样做,开发者只能自己创建一个新表,并把数据迁移过去。

  GYDataCenter同样能自动创建及修改数据库索引,开发者只需实现下面方法。与property不同,已存在的索引是可以自动删除的。

  +(NSArray*)indices{

  return@[

  @[@"dateOfBirth"],

  @[@"department",@"name"]

  ];

  }

  关系型property及faulting

  如上面所示,持久化property的类型可以是另外一个model类型。比如Employee有一个属性department,该属性的类型为Department。这种属性称为关系型property。对于关系型property,必须在实现里定义为dynamic:

  @dynamicdepartment;

  对于上面的关系型property,GYDataCenter会在Employee的数据库表里添加一个column,用于存储department的主键值。当调用[employeesave]时,GYDataCenter会把department的主键值存在新插入的Employee数据库记录里。但是GYDataCenter不会把整个department存在Department表里。当开发者需要这样做时,需要显示地调用save:

  [employeesave];

  [employee.departmentsave];

  当开发者通过查询接口从GYDataCenter里拿出Empolyee对象时,属性department不会被完全赋值。属性department会指向一个Department对象,但该对象只有主键值被初始化了。当代码里第一次访问属性department时,department才被完全赋值,这个过程对开发者是透明的。这个机制叫faulting,与CoreData类似。

  Faulting机制避免了拿一个对象时把它所有的关系对象,以及关系对象的关系对象都拿出来。这样带来了两个好处:

  减少内存使用。

  提高查询性能。

  高性能cache层

  与FMDatabaseQueue建议的一致,GYDataCenter对于每一个数据库(dbName相同)的所有操作,都放在同一个队列排队执行,这样做既保证了线程安全,同时又保证了数据的一致性。实际上,GYDataCenter底层用的正是FMDatabaseQueue。

  为了提高性能,GYDataCenter还对model对象做了cache,cache以model对象的主键值为索引。开发者可以为每个model类型指定是否要cache,以及在memorywarning时是否要回收cache。GYDataCenter对于每一个数据库的所有cache的操作,同样也放在一个队列排队执行,具体流程如下:

  1)按主键的查询操作

  先到cache队列查询cache是否存在,存在则返回,不存在则同步到DB队列查询数据库,从DB队列返回后,回到cache队列先更新cache,然后再返回。

1.png



  2)按where的查询操作

  先进cache队列,通过cache队列同步调起DB队列查询数据库,并组装对象。在组装对象时,对于每一条记录先拿出主键值到cache查询一下对象是否存在,如果存在则直接使用,不存在则生成新的对象,并拿出其它column值以初始化新生成的对象。所有对象组装完后,返回cache队列,更新cache并返回。

  3)写操作

  先到cache队列更新cache,然后异步调起DB队列执行数据库操作。

2.png



  自动批量写入

  我们都知道,当数据库连续执行多个写操作时,可以通过事务(transaction)把多个写操作包在一起,一次性写入磁盘以提高性能。GYDataCenter利用这点,自动地把多个DB操作包在一个事务中,以提高性能。

  前面说过,对于同一个数据库的所有操作,都放到一个队列排队执行。由于对于同一个数据库,只有一个数据库句柄,且只有一个线程,使得自动批量写入DB成为可能。当数据库连接建立时,GYDataCenter即马上开始一个事务,并且每隔一个固定的时间(默认1秒),GYDataCenter就会把事务提交后再马上开始一个新的事务。

  这种优化对于写操作频繁的情况特别有效,当然,对于读操作也是有帮助的。如果不手动加事务,SQLite会为每个SQL的执行创建一个事务,把多个SQL的执行包在一个事务中,避免了创建多个事务的开销。

  虽然不断地定时提交事务,GYDataCenter仍然支持多个请求的原子操作。GYDataCenter提供了-inTransaction:dbName:接口,在该接口的开始,GYDataCenter会把定时事务提交暂停,并把上一个事务提交掉。接着,把参数block里的多个操作包在一个事务里,并在该接口结束时恢复定时事务提交。

  ANALYZE优化查询

  ANALYZE是SQLite提供的一个工具,执行ANALYZE命令后SQLite会收集数据和索引的统计信息,并将这些统计信息存于数据库文件的一个内部表里(sqlite_stat1)。这些统计数据可以帮助SQLite在执行SQL时选择更优的策略,从而提高数据库性能。

  ANALYZE命令产生的统计数据不会自动更新,随着数据库写操作的不断累积,这些统计信息会变得不准确,需要重新执行ANALYZE命令。根据这点,GYDataCenter统计写操作的次数,当写操作累计达到一定次数时(默认500),GYDataCenter会在app进入后台时执行一次ANALYZE命令,以此优化性能。

  ANALYZE命令的执行是比较快的,在实际项目的实践中发现,ANALYZE命令的执行时间是几十毫秒级别,因此,不必担心由于ANALYZE执行太慢导致app被系统kill掉。

文章来源:WeRead团队
文章作者:zepo

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部