add 2018/6/14
上一篇我讲述了LitePal建立表(创建数据库的流程),链接戳这里。这一篇看看LitePal是如何做到简便的升级数据库的。
加入你两张表Singer和Musiic,并且已经存了数据,结果发现Music表名字多打了一个 i ,Singer多了一个字段,并且想添加一张表Album,那么应该怎么做呢?使用过系统原生SQLite的人应该知道这将非常麻烦,但用LitePal却很简单,只需要按照“直觉”做:把Musiic类改名,把Singer类中多的字段删除,新建Album类并在litepal.xml中注册,最后将version加1并进行任何数据库操作就可以了。那么我们看他是如何实现的吧。
如上做过之后调用LitePal.getDataBase()会更新数据库,我在上一篇中讲过这个调用流程,这次由于在xml解析后得到的version比原version高,所以会在LitePalOpenHelper中执行onUpgrade:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Generator.upgrade(db);
SharedUtil.updateVersion(LitePalAttr.getInstance().getExtraKeyName(), newVersion);
}
第二行我就不展开了,很显然是将当前version以SharedPreferences进行存储,我们看Generator.upgrade(db):
static void upgrade(SQLiteDatabase db) {
drop(db);
create(db, false);
updateAssociations(db);
upgradeTables(db);
addAssociation(db, false);
}
简单的一行代码LitePal要进行五项操作,我先总体描述他们所做的工作:
(1)drop:将原本在mapping中声明但本次不在的表删除(最后总要更新Table_Schema,之后我不会再提了);
(2)create:将原本不在mapping中但本次添加的表创建;
(3)updateAssociations:若关联的两张表有任意一张被删除,将它们之间的关联删除;
(4)upgradeTables:更新实体类做了修改的表,如上面提到的删除某个字段;
(5)addAssociation:添加新产生的关联。
看似内容很多,但和创建表有很多相似之处,先来看
(1)Generator.drop(db):
private static void drop(SQLiteDatabase db) {
Dropper dropper = new Dropper();
dropper.createOrUpgradeTable(db, false);
}
Dropper.createOrUpgradeTable(db, false):
@Override
protected void createOrUpgradeTable(SQLiteDatabase db, boolean force) {
mTableModels = getAllTableModels();
mDb = db;
dropTables();
}
getAllTableModels这样的在上一篇提到过的方法就直接略过了,接下来是dropTables():
private void dropTables() {
List<String> tableNamesToDrop = findTablesToDrop();
dropTables(tableNamesToDrop, mDb);
clearCopyInTableSchema(tableNamesToDrop);
}
按照顺序,先看看如何判别哪些表需要删除:
private List<String> findTablesToDrop() {
List<String> dropTableNames = new ArrayList<String>();
Cursor cursor = null;
try {
cursor = mDb.query(Const.TableSchema.TABLE_NAME, null, null, null, null, null, null);//查询Table_Schema表所有数据
if (cursor.moveToFirst()) {
do {
String tableName = cursor.getString(cursor
.getColumnIndexOrThrow(Const.TableSchema.COLUMN_NAME));//表名
int tableType = cursor.getInt(cursor
.getColumnIndexOrThrow(Const.TableSchema.COLUMN_TYPE));//0普通表,1中间表
if (shouldDropThisTable(tableName, tableType)) {
// need to drop tableNameDB
LogUtil.d(TAG, "need to drop " + tableName);
dropTableNames.add(tableName);
}
} while (cursor.moveToNext());
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return dropTableNames;
}
private boolean shouldDropThisTable(String tableName, int tableType) {
return !BaseUtility.containsIgnoreCases(pickTableNamesFromTableModels(), tableName)
&& tableType == Const.TableSchema.NORMAL_TABLE;
}
findTablesToDrop()这个方法通过查询Table_Schema表,对存储的每个表名进行判断是否删除,将要删除表的表名全部放入一个List返回。判断的方法是shouldDropThisTable(String tableName, int tableType),会删除xml中不再存在且是普通类型的表。实际进行删除表的方法贴一下,我就不解释了,之前有类似的:
protected void dropTables(List<String> dropTableNames, SQLiteDatabase db) {
if (dropTableNames != null && !dropTableNames.isEmpty()) {
List<String> dropTableSQLS = new ArrayList<String>();
for (int i = 0; i < dropTableNames.size(); i++) {
dropTableSQLS.add(generateDropTableSQL(dropTableNames.get(i)));
}
execute(dropTableSQLS, db);
}
}
最后更新一下Table_Schema,一个drop操作就结束了。
(2)create(db, false):和创建表操作的create使用的是同一个方法,只是第二个参数不再是true而是false,还有印象的话,false表示对已经存在的表不做任何操作,只新建不存在的表。
(3)updateAssociations(db):
private static void updateAssociations(SQLiteDatabase db) {
AssociationUpdater associationUpgrader = new Upgrader();
associationUpgrader.addOrUpdateAssociation(db, false);
}
可能会觉得addOrUpdateAssociation这个方法比较眼熟&