软件迭代过程中,业务不断更新,也要求软件持续更新。相应地,数据库更新升级也是不可避免的一个环节。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. jsp 安全

    一.  身份验证和授权 认证是检验某人真正是他/她自称的那个人的过 程.在一个Servlet/JSP应用程序中,身份验证一般通过 检查用户名密码是否正确.授权是检查该级别的用户是 否具备访问权限.它适 ...

  2. VS2010 开发 VB6.0 activeX控件 dll

    项目源码 https://download.csdn.net/download/csdn_z_s/10427764 开发环境 操作系统: win7 64位 旗舰版 Java语言开发环境:  Eclip ...

  3. 在Windows环境下搭建Nginx文件服务器(简单实用版)

    为了解决项目组内容应用,打算把本地的e:tools目录共享出来,具体操作步骤如下1.下载安装包:http://nginx.org/download/nginx-1.9.15.zip2.解压缩3.修改配 ...

  4. 快速部署docker

    前言:docker就不用说了,好东西啊.更好的利用服务器的资源,各个服务是相互隔离的,文件的存放更加规律,也好清理空间及数据备份 docker安装-----社区版ce(免费的,另一版本收钱的) 系统: ...

  5. Mongodb字段自增长

    MongoClient client = new MongoClient("mongodb://xxx.xxx.x.xx:27017"); var mongServer = cli ...

  6. matplotlib figure图像-【老鱼学matplotlib】

    如果我们想要显示多个图像,有点类似多窗口显示图像这个概念,则就会用到plt.figure() 直接上例子: import numpy as np import pandas as pd import ...

  7. 配置maven项目的开发时的默认jdk版本

    配置所有maven项目的默认jdk版本,若不配置则提示"Warning:java: 源值1.5已过时, 将在未来所有发行版中删除" 在settings.xml文件中profiles ...

  8. Ubuntu在终端执行命令时出现的错误

    1.在安装jdk时无意间结束了安装进程,然后就提示这个错误 E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)E: 无法锁定管理目录(/var/lib/d ...

  9. angularJs实现数据双向绑定的原理

    angular1.x在指定的事件触发时(比如dom事件,xhr响应事件,浏览器定位变更事件,定时器事件),通过脏值检测的方式比对数据是否有变更,来决定是否更新视图. angular2使用了zone.j ...

  10. 在VS2010上安装MVC4(webApi)

    我们安装的VS2010上是没有MVC4或者WebApi的,要想加入这些功能只能自己在网上下载安装. 要安装MVC4,首先得安装VS10sp(Service Package)1,然后再安装MVC4.安装 ...