软件迭代过程中,业务不断更新,也要求软件持续更新。相应地,数据库更新升级也是不可避免的一个环节。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. linux ps top 命令 VSZ,RSS,TTY,STAT, VIRT,RES,SHR,DATA的含义

    VIRT:virtual memory usage 虚拟内存1.进程“需要的”虚拟内存大小,包括进程使用的库.代码.数据等2.假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而 ...

  2. 编辑技巧分享如何给PDF添加注释

    纸质的文件想要添加注释就直接拿笔在上面添加就好了,那么电子文件要怎么添加注释呢,今天小编就以我们现在经常使用到的PDF文档来为大家分享怎么添加注释.   1. 我们需要在百度中搜索并下载并安装一款PD ...

  3. Ubuntu下 安装MiniGUI

    1. 需要下载的组件 首先需要这些安装包,这些安装包可以在MiniGUI官网上下载. libminigui-gpl-3_0_12.tar.gzmg-samples-3_0_12.tar.gzfreet ...

  4. 办公用品管理系统VB——库存数量导出EXCEL,SaveEXCEL

    办公用品管理系统VB——库存数量导出EXCEL,SaveEXCEL 总体来说,VB的EXCEL导出效率还是蛮低的,就是一个小型化的办公用品管理软件,不再优化了. 时间紧迫,就没有从头到尾的用C#编写, ...

  5. [转] Vue + Webpack 组件式开发(练习环境)

    前言 研究了下别人的 vue 多页面框架, 都是直接复制 package.json 文件,然后在本地 npm install 一下即可, 或者使用官网 vue-cli 工具生成一个项目, 觉得这样虽然 ...

  6. Java是解释型还是编译型语言?

    有人说Java是编译型的.因为所有的Java代码都是要编译的,.java不经过编译就无法执行. 也有人说Java是解释型的.因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释型 ...

  7. Android+openCV 动态人脸检测

    动态人脸检测前提是需要打开摄像头. 网上看了很多教程,我知道的有两种方式打开摄像头: JavaCameraView mCameraView = new JavaCameraView(this, -1) ...

  8. Laravel 5 中间件、路由群组、子域名路由、 权限控制的基本使用方法

    创建控制器: php artisan make:controller Admin/IndexController 创建Middleware: php artisan make:middleware T ...

  9. PSO:利用PSO+ω参数实现对一元函数y = sin(10*pi*x) ./ x进行求解优化,找到最优个体适应度—Jason niu

    x = 1:0.01:2; y = sin(10*pi*x) ./ x; figure plot(x, y) title('绘制目标函数曲线图—Jason niu'); hold on c1 = 1. ...

  10. Beta(7/7)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...