软件迭代过程中,业务不断更新,也要求软件持续更新。相应地,数据库更新升级也是不可避免的一个环节。Android作为客户端应用,数据库升级相对于服务端来说会麻烦一些。常见的升级方式有:

1.删除旧表和数据,创建新表。优点是简单方便,缺点是丢失了旧数据。适用于应用数据依赖度低的情况。

2.在代码中兼容处理各版本数据库,创建新表,迁移旧数据到新表。优点是保留了旧数据,缺点是需要处理兼容个版本数据库差异,比较麻烦。如果通过代码来记录维护版本差异,会导致代码臃肿且极易出错。

本文介绍一种简单无缝的数据库升级方案,也是属于上述的第二种方式,但是简单、高效地处理了数据库版本兼容。代码已实现在DBFramework中,这是一个轻量的数据库框架,简单、规范、高效,能够很好的处理表之间的继承关系,可以为你节省很多开发工作。

感兴趣的朋友可以了解一下。

数据库升级,其实是对其中的表进行升级。要更新表并且保留数据,这就必须要知道新表和旧表之间的差异。如果我们靠开发人员来记录各版本之间表的差异,无疑是一个困难和繁杂的工作。那么当我们进行数据库的时候,客户端应用有没有办法知道这些差异,知道有哪些表需要更新呢?答案是肯定的。在Sqlite中有一张叫做sqlite_master的系统表,其中记录了sqlite中的所有表信息,如下:

可以看到,其中除了表名,还有表创建语句。有了创建语句,我们就能解析出表的字段信息,然后对比新表和旧表的字段,有差异则说明表需要更新,反之则不需要更新。如下代码用来获取现有的表信息:

/**
* Get old tables.
* @return A map contains old tables which takes table name as key.
*/
public Map<String, Table> getOldTables() {
final String table = "sqlite_master";
final String[] columns = {"name", "sql"};
Cursor cursor = mDB.query(table, columns, "type='table'", null, null, null, null);
HashMap<String, Table> ret = null;
if (cursor.getCount() > 0) {
ret = new HashMap<String, Table>(cursor.getCount());
Table tmp;
while (cursor.moveToNext()) {
tmp = new Table(cursor.getString(0), cursor.getString(1));
ret.put(tmp.Name, tmp);
}
}
cursor.close();
return ret == null ? Collections.EMPTY_MAP : ret;
}

Table是一个记录表信息的类,拿到现有表信息,就可以和新的表信息进行对比,主要对比表字段的变化:

  public class Table {

   ...

  public boolean equalsColumns(Table table) {
String myColumns = getColumnsStatement(CreateSql).toUpperCase();
String columns = getColumnsStatement(table.CreateSql).toUpperCase();
return (myColumns.equals(columns));
} ... }

如果无变化则跳过,有变化则更新,更新过程为:

1.将现有表以别名命名

2.创建新表

3.迁移数据

4.删除现有表

如下代码所示:

 @Override
protected void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion, List<Table> tableList) {
Map<String, Table> oldMap = getOldTables();
Iterator<Table> iterator = tableList.iterator();
Table table;
Table oldTable;
String tempTable;
while (iterator.hasNext()) {
table = iterator.next();
if ((oldTable = oldMap.get(table.Name)) == null) {
//New table, create directly.
db.execSQL(table.CreateSql);
Log.i(TAG, "Table " + table.Name + " is a new table. Create it directly");
continue;
}
//Remove hit table.
oldMap.remove(table.Name);
if (oldTable.equalsColumns(table)) {
//Table not change.
Log.i(TAG, "Table " + table.Name + " doesn't need update");
continue;
}
tempTable = table.Name + TEMP_SUFFIX;
Log.i(TAG, "Update table: " + table.Name); //Table changed.
//Alter old table as temp.
alterTableName(oldTable.Name, tempTable);
//Create new table.
db.execSQL(table.CreateSql);
//Copy data.
copyData(getCommonColumn(oldTable.getColumns(), table.getColumns()), tempTable, table.Name);
//Delete old table
deleteTable(tempTable);
}
//Delete obsolete tables not hit.
deleteObsoleteTables(oldMap.values());
}

更多细节可查看源码:DBFramework

这种方案简单方便,而且几乎一劳永逸。推荐小伙伴们使用,如果有更好的方式或者宝贵意见,欢迎交流。

Android数据库无缝升级方案的更多相关文章

  1. Android 实现应用升级方案(暨第三方自动升级服务无法使用后的解决方案)

    第三方推送升级服务不再靠谱: 以前在做Android开发的时候,在应用升级方面都是使用的第三方推送升级服务,但是目前因为一些非技术性的问题,一些第三方厂商不再提供自动升级服务,比如友盟,那么当第三方推 ...

  2. Android数据库(sqlite)加密方案

    最近因为一些项目的安全性需要将数据库加密,一开始想到的就是先将数据库通过AES加密,然后运行时再解密,另一种是将数据库里的内容加密. 很快这两种方案都是不理想的,第一种加密方式形同虚设,第二种,如果加 ...

  3. android 数据库的升级与降级解决方案

    在我们写的程序中不避免的需要升级.或者说需要改变业务逻辑,那这个时候就需要修改数据库的字段,来适应不同的表结构 我们一般写数据库都是操作一个继承至 SQLiteOpenHelper 的类 然后我们需要 ...

  4. Android数据库升级

    随着Android应用版本的迭代,经常遇到数据库表结构发生改变,或者一些指定的表数据需要更新.这也就引出一个问题Android数据库的更新问题. Android数据库升级分类 Android数据库更新 ...

  5. 优雅的处理Android数据库升级的问题

    原始完成于:2015-04-27 19:28:22 提供一种思路,优雅的处理Android数据库升级的问题,直接上代码: 1 package com.example.databaseissuetest ...

  6. Android 数据库升级解决方案

    转自:http://blog.csdn.net/leehong2005/article/details/9128501 请考虑如下情况: 在数据库升级时,不同版本的数据库,他们定义的表结构完全可能是不 ...

  7. Android版本升级同时Sqlite数据库的升级及之前数据的保留

    http://www.cnblogs.com/wang340/archive/2013/05/06/3063135.html http://www.eoeandroid.com/forum.php?m ...

  8. Android(java)学习笔记192:SQLite数据库(表)的创建 以及 SQLite数据库的升级

    一.数据库的创建 1.文件的创建      //引用,如果文件不存在是不会创建的   File  file = new File("haha.txt"):     //输出流写数据 ...

  9. Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())[4]

    数据库版本升级对软件的管理操作. 我们手机经常会收到xxx软件升级什么的提醒,你的软件版本更新,同时你的数据库对应的版本也要相应的更新. 数据库版本更新需要主要的问题: 软件的1.0版本升级到1.1版 ...

随机推荐

  1. php 安装redis php扩展

    下载文件 下载上面文件解压并拷贝至php的ext目录下 如果 PHP版本不对 接下来根据你所拟定的版本去如下这两个网址下载文件 1.http://windows.php.net/downloads/p ...

  2. SSH阅读笔记

    1.SSH单阶人脸段检测器,在不同层检测不同scale的人脸,而不是使用mtcnn中金字塔的方式,从而实现加速. 2.SSH的整体结构,3个module的stride分别为8,16,32,使用不同的感 ...

  3. 将日志备份推送到s3存储上

    1.将日志备份推送到s3存储上 #!/bin/sh # 此脚本实现将/usr/local/netqin/boss/netqin/logs/BOSS_ContentServer/BOSS_AD_SDK ...

  4. 一些值得深入学习和借鉴的 .Net 开源项目

    1.DotNetFramework  .NET Reference Source 发布了 beta 版,可以在线浏览 .NET Framework 4.5.1 的源代码,并且可以通过配置,在 Visu ...

  5. Python学习(三十三)—— Django之ORM

    Object Relational Mapping(ORM) 一.ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系 ...

  6. Codeforces 755F PolandBall and Gifts bitset + 二进制优化多重背包

    PolandBall and Gifts 转换成置换群后, 对于最大值我们很好处理. 对于最小值, 只跟若干个圈能否刚好组能 k 有关. 最直观的想法就是bitset优化背包, 直接搞肯定T掉. 我们 ...

  7. 1.使用RNN做MNIST分类

    第一次用LSTM,从简单做起吧~~ 注意事项: batch_first=True 意味着输入的格式为(batch_size,time_step,input_size),False 意味着输入的格式为( ...

  8. 解决Mysql命令行输入密码闪退问题

    输入密码闪退是因为后台Mysql服务没有启动. 解决办法:我的电脑,右键管理,服务,查看服务里面Mysql是否在运行.如果没有在运行那么可以右键启动,最好属性中设置为自动启动.

  9. 大数据项目之_15_帮助文档_NTP 配置时间服务器+Linux 集群服务群起脚本+CentOS6.8 升级到 python 到 2.7

    一.NTP 配置时间服务器1.1.检查当前系统时区1.2.同步时间1.3.检查软件包1.4.修改 ntp 配置文件1.5.重启 ntp 服务1.6.设置定时同步任务二.Linux 集群服务群起脚本2. ...

  10. angular笔记_10

    过滤器 currency:1:2:3                     与货币相关 第一个参数是符号 第二个参数是保留小数点几位 number:1                         ...