注:使用sdk版本为3.2.2
1. model的主键如果是数字类型,必须使用封装类型
greendao 查询方法 XXXDao
的生成是使用greendao-generator
中的dao.ftl
为模板生成的
@Override
public boolean hasKey(${entity.className} entity) {
<#if entity.pkProperty??>
<#if entity.pkProperty.notNull>
throw new UnsupportedOperationException("Unsupported for entities with a non-null key");
<#else>
<#if entity.protobuf>
return entity.has${entity.pkProperty.propertyName?cap_first}();
<#else>
return entity.get${entity.pkProperty.propertyName?cap_first}() != null;
</#if>
</#if>
<#else>
// TODO 使用 notNull的判断会直接判断 xxx != null, 数字类型生成模板就是错误的
return false;
</#if>
}
2. AbstractDao.save() 使用范围
- pk为自增状态下不设置 pk的保存
- 当前model已存数据库,需要更新
public void save(T entity) {
if (hasKey(entity)) {
update(entity);
} else {
insert(entity);
}
}
3. AbstractDao的缓存机制
AbstractDao除了使用方便外,还构建了自己的缓存机制
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap)
//IdentityScopeType Session, None
//DaoConfig
@SuppressWarnings("rawtypes")
public void initIdentityScope(IdentityScopeType type) {
if (type == IdentityScopeType.None) {
identityScope = null;
} else if (type == IdentityScopeType.Session) {
if (keyIsNumeric) {
identityScope = new IdentityScopeLong();
} else {
identityScope = new IdentityScopeObject();
}
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
//AbstractDao
public T load(K key) {
assertSinglePk();
if (key == null) {
return null;
}
if (identityScope != null) {
T entity = identityScope.get(key);
//获取缓存中entity
if (entity != null) {
return entity;
}
}
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
Cursor cursor = db.rawQuery(sql, keyArray);
return loadUniqueAndCloseCursor(cursor);
}
/** Internal use only. Considers identity scope. */
final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
if (identityScopeLong != null) {
if (offset != 0) {
// Occurs with deep loads (left outer joins)
if (cursor.isNull(pkOrdinal + offset)) {
return null;
}
}
long key = cursor.getLong(pkOrdinal + offset);
T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(entity);
if (lock) {
identityScopeLong.put2(key, entity);
} else {
identityScopeLong.put2NoLock(key, entity);
}
return entity;
}
} else if (identityScope != null) {
K key = readKey(cursor, offset);
if (offset != 0 && key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(key, entity, lock);
return entity;
}
} else {
// Check offset, assume a value !=0 indicating a potential outer join, so check PK
if (offset != 0) {
K key = readKey(cursor, offset);
if (key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
}
T entity = readEntity(cursor, offset);
attachEntity(entity);
return entity;
}
}
//AbstractDao中只要调用这两个方法,就会把查询结果加入缓存中
//如果同时对获取到的结果进行修改,缓存中的model就会相应变化
//AbstractDao.queryRaw()不涉及缓存, queryBuilder方法会使用缓存数据
4. 执行SQL语句无效
5. Cursor的内存泄露
GreenDao封装好了查询,cursor的生成与关闭都是在 AbstractDao中进行的,那么多线程操作时就可能会存在内存泄露的可能性。现在还没有好的解决方法
网友评论