GreenDao系列之(2)设计及机制介绍

简介: # 总体设计类图 ![这里写图片描述](http://img.blog.csdn.net/20170214183411203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmlsbHBpZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

总体设计类图

这里写图片描述

以下会分拆成两个部分进行说明:
1、总体机制部分
2、Sql操作细节部分

总体机制

image

可以看到,有几个重要的类:

  1. AbstractDaoMaster : 总入口类,每个db有相应的AbstractDaoMaster去管理,一般情况下用于创建AbstractDaoSession,并且创建xxxDao的DaoConfig,然后交给AbstractSession进行xxxDao的实例创建。
  2. Database :db抽象接口,有标准的sql实例及sqlcipher加密后的两者实例
  3. AbstractSession :db会话,一个AbstractDaoMaster可以创建多个会话,每个会话拥有该该db下的所有AbstractDao实例,并且决定AbstractDao实例是否使用缓存机制。很难想象多个会话是用在什么场景,一般情况下只会有一个会话。
  4. AbstractDao :数据库table的实体类,用于访问该table的所有操作。AbstractDao有两个泛型,第一个是主键类型,第二个是Entity的类型。AbstractDao提供了增删改查的所有操作,由于对象是Entity,因此修改的value全部以Entity给予的值为准,也就是说每次进行修改的时候,对应的行数据都会以Entity的值进行覆盖。
  5. DaoConfig :数据库table的配置定义,是greenDao的一个重要类。DaoConfig会在AbstractDaoMaster中通过registerDaoClass进行注册。在创建DaoConfig时候,通过反射机制读取xxxDAO的属性,从而生成xxxDao的配置(如column、主键、表名、增删改的语句等信息),用于数据库的增删改查曾操作。
  6. Property :数据库的column定义
  7. IdentityScope :很多人看到这个比较难于理解,按官方的解释:Identity scopes let greenDAO re-use Java objects. 说白了,就是一个缓存类。有两个缓存的类型:
  • IdentityScopeLong
  • IdentityScopeObject
    主要是根据AbstractDao的主键类型选择的,如果主键是Integer、Long,可以IdentityScopeLong,其他使用IdentityScopeObject。可以IdentityScopeLong内部使用自己编写的经过优化过的LongHashMap作为存储对象,效率会更高。

操作细节设计

这里写图片描述

前面提到DaoConfig是table的配置,其中的配置包括增删改语句的生成。AbstractDao作为table的入口,增删改的操作全部依赖于DaoConfig里的TableStatements。TableStatements包含了几条语句模板:

  1. insertStatement
  2. insertOrReplaceStatement
  3. updateStatement
  4. deleteStatement
  5. countStatement
    用于语句的快速获取。每条语句都是已经生成好的一条sql语句模板,AbstractDao使用时,只需要拿到该模板,然后进行数据的绑定就可以生成最终的sql语句。例子如下:
public DatabaseStatement getInsertOrReplaceStatement() {
    if (insertOrReplaceStatement == null) {
        String sql = SqlUtils.createSqlInsert("INSERT OR REPLACE INTO ", tablename, allColumns);
        DatabaseStatement newInsertOrReplaceStatement = db.compileStatement(sql);
        synchronized (this) {
            if (insertOrReplaceStatement == null) {
                insertOrReplaceStatement = newInsertOrReplaceStatement;
            }
        }
        if (insertOrReplaceStatement != newInsertOrReplaceStatement) {
            newInsertOrReplaceStatement.close();
        }
    }
    return insertOrReplaceStatement;
}

因此,可以看到,插入、更新的时候,虽然可以获取模板生成语句,但也比较笨拙,不支持灵活的根据属性进行更新的操作:假设我们想只更新AbstractDao的某个property,那就只能老老实实的写sql语句的,这点实在是坑!

而最最复杂的查询语句,则是通过QueryBuilder强大的功能进行查询。greenDao查询、更新的操作都是必须每次针对所有column进行操作,不支持部分column的查询和更新。从查询上确实应该如此,因此,在查询的时候,只需要提供灵活的where条件及order等条件供用户输入即可。

QueryBuilder主要包括两部分:

  1. 语句参数
  2. 生成语句并进行查询

语句参数

语句参数包含如下部分

private final WhereCollector<T> whereCollector; //where语句
 
private StringBuilder orderBuilder; //order标识

private final List<Object> values; //具体where值
private final List<Join<T, ?>> joins; //join值
private final AbstractDao<T, ?> dao;
private final String tablePrefix;

private Integer limit; //limit
private Integer offset; //offert
private boolean distinct;

其中WhereCollector是一个WhereCondition集合,WhereCondition包含两个接口:appendTo及appendValuesTo,用于生成最终的where语句。举个例子,And ProprotyCondition是这样生成的:

  
@Override
public void appendTo(StringBuilder builder, String tableAlias) {
    SqlUtils.appendProperty(builder, tableAlias, property).append(op);
}
        
public static StringBuilder appendProperty(StringBuilder builder, String tablePrefix, Property property) {
    if (tablePrefix != null) {
        builder.append(tablePrefix).append('.');
    }
    builder.append('"').append(property.columnName).append('"');
    return builder;
}

QueryBuilder会根据查询的类型生成不同的AbstractQuery,通过AbstractQuery的查询,最终得到查询结果。这里有个很重要的一个类AbstractQueryData。很容易造成误解成AbstractQuery查询得到的数据,其实不是,AbstractQueryData是AbstractQuery的多线程缓存,用于缓存不同的线程下的查询语句。用于查询语句的复用,这也是greenDao高效的原因。

总结

总的来说,

  1. greenDao相比其他ORMLite高效,比原生sql效率低,基于2个原因:
  • 初始化时采用一次反射,一次性构建好DaoConfig,最小化反射带来的负面效果。而其他ORM有些则生成sql语句时每次都使用反射,效率低也是难免的。
  • 缓存使用: Entity缓存、语句缓存复用
  1. greenDao的查询能够比较强大,但反之Update的操作则比较粗糙,有点不友好。
  2. 数据库的创建和更新也未涉及,既然用到了对象,那么就可以根据对象的属性进行数据库的创建及更新。(该点会在以后介绍我的方案)
目录
相关文章
|
3月前
|
SQL 数据处理 数据库
提升数据处理效率:深入探讨Entity Framework Core中的批量插入与更新操作及其优缺点
【8月更文挑战第31天】在软件开发中,批量插入和更新数据是常见需求。Entity Framework Core 提供了批处理功能,如 `AddRange` 和原生 SQL 更新,以提高效率。本文通过对比这两种方法,详细探讨它们的优缺点及适用场景。
105 0
|
3月前
|
数据库连接 数据库
Entity Framework Core 中的延迟加载与即时加载大揭秘!性能考量全知道,助你高效开发!
【8月更文挑战第31天】Entity Framework Core (EF Core) 是一款强大的对象关系映射(ORM)框架,支持延迟加载与即时加载两种方式。延迟加载即访问关联实体时再加载,适用于减少初始查询负载,但可能导致多次数据库查询;即时加载则在查询主实体时一并加载关联实体,减少数据库访问次数,但可能增加初始查询复杂度。选择加载方式需综合考虑查询复杂性、数据量及数据库连接管理等因素。
75 0
|
3月前
|
测试技术 数据库
确保数据访问层的可靠性:详细解析使用Entity Framework Core进行隔离的单元测试方法
【8月更文挑战第31天】在软件开发中,单元测试是确保代码质量的关键。本文通过一个在线商店的商品查询功能案例,介绍了如何使用EF Core和Moq框架实现数据访问层的隔离测试。通过模拟`ApplicationDbContext`,我们能够在不访问真实数据库的情况下对`ProductService`进行单元测试,提高测试效率并保证测试稳定性。这种方法是实现高效、可靠单元测试的重要手段。
52 0
|
4月前
|
消息中间件 负载均衡 Java
Java中设计和优化消息传递系统的策略
Java中设计和优化消息传递系统的策略
|
Java 数据库连接 数据库
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤(下)
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
107 1
|
Java 数据库连接 数据库
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤(上)
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
140 1
|
Java 数据库连接 数据库
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
177 0
高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
|
存储 SQL Java
XOrmlite 一个方便实用的OrmLite数据库框架,支持一键集成
XOrmlite 一个方便实用的OrmLite数据库框架,支持一键集成
313 0
XOrmlite 一个方便实用的OrmLite数据库框架,支持一键集成
|
数据库
Entity Framework 并发冲突解决方案(上)
Entity Framework 并发冲突解决方案
201 0
Entity Framework 并发冲突解决方案(上)
|
存储 Java API
一文详解 Android状态机StateMachine 使用方式及实现原理
`StateMachine`不是`Android SDK`中的相关API,是存在于`frameworks`层源码中的一个Java类。通过这篇文章探究一下其使用方式以及实现原理。
1100 0
一文详解 Android状态机StateMachine 使用方式及实现原理