几百年不写博客了,而刚好又一晚上失眠,可能由于刚放完假,还没适应过来吧,反正也睡不着就想着早起写篇文章记录下工作中遇到的一些问题,也顺便静下心,好让自己快速投入工作中。
由于以前做的APP都是小型的,所以对数据库的使用程度不高,一直用自带的手写数据库即可。去年9月份开始加入一个项目的开发,用到了数据库greendao,由于之前没用过,所以做之前查看了相关的资料,但是当做了之后才发现原来坑也挺大。
greendao由于是orm框架,所以对数据库的操作确实是非常方便的,但是同时也存在一些问题,比如数据的读取,它是有缓存的,你会发现你存了一条数据后再去读取数据,结果并没有你刚插入的那条数据,原因是存在缓存,所以需要清理下缓存,其实这也不算是问题和BUG,应该是设计的初衷是为了一些常规不经常修改的数据,为了读取数据更快才加入的缓存,自己清理下缓存再读取即可。
废话不多说了,重点,每次我们更新数据库之后,比如新增字段、删减字段,需要对数据库的版本号进行增加,这样greendao才知道我们修改了数据库,需要进行数据库的升级,但是问题来了,greendao每次升级数据库都是把本地数据库全部重清空了,表也删了,然后再根据你新版本的表实体来新建新的数据库表,这样就会导致你的数据无法保留,每次一旦有数据库的更新,都会导致数据的丢失,所以网上出现了一些大神写的工具类,实现的思路其实也很简单,首先要屏蔽掉greendao的默认升级功能,然后:
1.首先创建临时表(字段名和属性跟旧表一模一样);
2.遍历所有表,把对应表的数据插入到临时表中;
3.删除原表,新建新表;
4.把临时表数据插入到新表中,然后删除临时表;
以上四个步骤就是网上最公认的数据库升级方式,实现的工具类代码如下:
package com.android.sdongpo.db;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import com.android.sdongpo.gen.DaoMaster;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.internal.DaoConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
}
return instance;
}
private static List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch