强大的模型缓存

在这个库模型缓存是很简单的,是非常可扩展的,可获取和使用。

ModelCache是一个用sqlite查询实现的缓存接口,FlowQueryListFlowCursorList,或者其他你想使用它的任何地方。

在表中启用高速缓存

只要增加 cachingEnabled = true在你得@Table注解中就可以启用表的高速缓存。要启用类缓存多列@PrimaryKey,你必须定义一个@MultiCacheField对象(下文解释)。

当查询在数据库运行时,它将在缓存中存储模型的实例,并且缓存是一个有效的内存管理单独负责的。

有几种缓存方式: There are a few kinds of caches supported out the box:

  1. ModelLruCache -> 使用LruCache, Lru规则自动对内存进行管理。
  2. SimpleMapCache -> 简单存储models在预定容量的Map中(默认为HashMap中)。
  3. SparseArrayBasedCache -> 一个基于SparseArray下的int->object key/value 类型。它适用于任何数量的后代或基本对应(Integer, Double, Long等),或MulitCacheConverter返回相同的密钥类型。

注意 如果你运行一个带有字段的 SELECT ,你也可以缓存整个Model 。强烈建议只加载在这种情况下全款,因为缓存机制将弥补最效率的问题。

默认的缓存是 SimpleMapCache。你可以在 @Table指定 cacheSize() 来设置默认缓存的内容的大小。一旦指定自定义缓存,此参数无效。

要使用自定义缓存, 在Model类中指定缓存:

  1. @ModelCacheField
  2. public static ModelCache<CacheableModel3, ?> modelCache = new SimpleMapCache<>();

@ModelCacheField 必须是公共静态。

作为3.0,现在DBFlow从缓存加载时巧妙地重新加载@ForeignKey 的关系。

缓存到底是如何工作

1.每个@Table/Model类都有其自己的缓存,它们表与表和父类与之类之间不共享。

  1. 它“拦截”查询运行并引用缓存(下面解释)。
  2. 当表中使用了任何包含 Insert, Update, 或者 Delete 方法,将强烈建议不要进行缓存,当运行这些方法后,模型作为缓存将不会更新(因为效率和性能方面的原因)。如果您需要运行这些操作,一个简单的FlowManager.getModelAdapter(MyTable.class).getModelCache().clear() 运行后,查询的缓存将失效,它将会继续更新其信息。
  3. 从缓存中修改对象遵循Java引用的规则:在一个线程中更改字段值可能导致您的应用程序数据数据不一致,直到save(), insert() or update()方法运行,才会重新到数据库加载正确的数据。更改任何字段直接从缓存中修改对象(当从它直接加载),所以多加留意。

当通过包装语言运行查询,DBFlow将:

  1. 运行查询,从而产生一个游标
  2. 通过游标检索主键列值
  3. 如果组合键是在高速缓存中,我们:
    1. 刷新关系,如@ForeignKey(如果存在的话)。提示:通过表缓存使此更快地实现这一目。
    2. 然后返回缓存的对象。
  4. 如果对象不存在,我们从DB加载完整的对象,和随后的查询到相同的对象将从缓存返回对象(直到它驱逐或从高速缓存清除。)

多主键缓存

在3.0,DBFlow支持的高速缓存的多个主密钥。它需要那些有一个以上的主键的模型定义一个@MultiCacheField

  1. @Table(database = TestDatabase.class, cachingEnabled = true)
  2. public class MultipleCacheableModel extends BaseModel {
  3. @MultiCacheField
  4. public static IMultiKeyCacheConverter<String> multiKeyCacheModel = new IMultiKeyCacheConverter<String>() {
  5. @Override
  6. @NonNull
  7. public String getCachingKey(@NonNull Object[] values) { // in order of the primary keys defined
  8. return "(" + values[0] + "," + values[1] + ")";
  9. }
  10. };
  11. @PrimaryKey
  12. double latitude;
  13. @PrimaryKey
  14. double longitude;
  15. @ForeignKey(references = {@ForeignKeyReference(columnName = "associatedModel",
  16. columnType = String.class, foreignKeyColumnName = "name", referencedFieldIsPackagePrivate = true)})
  17. TestModel1 associatedModel;
  18. }

返回类型可以是任何东西,要ModelCache定义的类支持返回类型。

FlowCursorList + FlowQueryList

@Table/Model相关缓存中,FlowCursorListFlowQueryList 利用单独 的ModelCache,该覆盖默认的缓存机制:

  1. @Override
  2. protected ModelCache<? extends BaseCacheableModel, ?> getBackingCache() {
  3. return new MyCustomCache<>();
  4. }

自定义缓存

只要你想的话,你可以创建自己的缓存并使用它。

一个从支持库复制的LruCache缓存使用例子: An example cache is using a copied LruCache from the support library:

  1. public class ModelLruCache<ModelClass extends Model> extends ModelCache<ModelClass, LruCache<Long, ModelClass>>{
  2. public ModelLruCache(int size) {
  3. super(new LruCache<Long, ModelClass>(size));
  4. }
  5. @Override
  6. public void addModel(Object id, ModelClass model) {
  7. if(id instanceof Number) {
  8. synchronized (getCache()) {
  9. Number number = ((Number) id);
  10. getCache().put(number.longValue(), model);
  11. }
  12. } else {
  13. throw new IllegalArgumentException("A ModelLruCache must use an id that can cast to" +
  14. "a Number to convert it into a long");
  15. }
  16. }
  17. @Override
  18. public ModelClass removeModel(Object id) {
  19. ModelClass model;
  20. if(id instanceof Number) {
  21. synchronized (getCache()) {
  22. model = getCache().remove(((Number) id).longValue());
  23. }
  24. } else {
  25. throw new IllegalArgumentException("A ModelLruCache uses an id that can cast to" +
  26. "a Number to convert it into a long");
  27. }
  28. return model;
  29. }
  30. @Override
  31. public void clear() {
  32. synchronized (getCache()) {
  33. getCache().evictAll();
  34. }
  35. }
  36. @Override
  37. public void setCacheSize(int size) {
  38. getCache().resize(size);
  39. }
  40. @Override
  41. public ModelClass get(Object id) {
  42. if(id instanceof Number) {
  43. return getCache().get(((Number) id).longValue());
  44. } else {
  45. throw new IllegalArgumentException("A ModelLruCache must use an id that can cast to" +
  46. "a Number to convert it into a long");
  47. }
  48. }
  49. }