Android 数据库升级完整解决方案

数据库升级的意义

我们在开发Android应用的时候,不可避免地要使用数据库。而数据库的结构在第一版的时候定下来,之后发布功能更新,或增加业务逻辑,原来的数据库结构可能就不适用了。而如果数据库的结构与之前版本的结构不同,新版本的应用读取旧数据库肯定会出问题。解决办法只有两种:

1.让用户卸载老版本再安装新的程序;

2.软件自行更新数据库结构。

第一种办法很明显不具备可操作性,而且用户一旦卸载软件,数据就丢失了,这是不能容忍的事情。因此,作为开发者必须妥善处理数据库的升级问题。

当然了,有的同学会说,这问题没意义嘛。我们在设计软件的时候就把数据库设计得完备一点就好了,一开始就考虑周全,以后再也不用管升级的事情。这种方法理论上虽然可行,但实际操作起来是非常困难的,除非你在开发定制软件(例如某些和硬件结合的产品,其硬件发布之后就不再更新或很少更新,这样的软件确实没多大改动)。对于面向市场的应用来说,很可能在立项之初根本不会知道以后会增加哪些功能。这样,我们终究还是要面对这个问题。

保留数据的升级

现在以一个假想的程序数据库来谈如何保留原有的数据库进行升级。为直观起见,这里在每次软件版本安装之后导出了数据库文件,并使用SQLite Studio显示表结构和内容,过程从略。并且为了代码的简洁,省略了一些异常处理。我们假设数据库有这样三个版本:

v1:t_user(username, password);

v2:t_user(username, password), t_region(region, code);

v3:t_user(username, password), t_region(region, code, country);

可以看出,第一次升级增加了一张表,而第二次升级修改了表的定义。

创建和升级数据表的基本知识

我们在使用数据库之前,基本上会自定义一个类继承自SQLiteOpenHelper。该类的其中一个构造函数形式是这样的(另一个多出来一个DatabaseErrorHandler):

    public SQLiteOpenHelper(Context context, String name, 
                    CursorFactory factory, int version) {
        this(context, name, factory, version, null);
    }

这个构造函数里面的version参数即是我们设定的版本号。第一次使用数据库时传递的这个版本将被系统记录,并调用SQLiteOpenHelper#onCreate()方法进行建表操作。后续传入的版本如果比这个高,则会调用SQLiteOpenHelper#onUpgrade()方法进行升级。

增加一张表

很明显,增加新表(或者删除没有外键的表)的操作代价很小,只需要在onUpgrade()中写好建表操作和插入初始数据就好了。

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		if (oldVersion==1){
			db.execSQL("CREATE TABLE t_region(_id integer primary key"
			 + "autoincrement, region varchar, code varchar)");
			//insert data...
		}
	}

从上面的图里可以看到,新版本的数据库中已经有t_region表了。

修改表定义

SQLite数库对ALTER TABLE命令支持非常有限,只能在表末尾添加列,不能修改列定义,不能删除已有的列。那么如果要修改表呢?我们可以采用临时表的办法。具体来说有四步:

  1. 将现有表重命名为临时表;
  2. 创建新表;
  3. 将临时表的数据导入新表(注意处理修改的列);
  4. 删除临时表。

以例子中的v2升级到v3为例:

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		if (oldVersion==2){
			db.execSQL("ALTER TABLE t_region RENAME TO t_region_temp");
			db.execSQL("CREATE TABLE t_region(_id integer primary key"
			     + "autoincrement, region varchar, code varchar, "
			     + "country varchar)");
			db.execSQL("insert into t_region(_id, region, code, country) " 
			    + "select _id, region, code, \"CHINA\" from t_region_temp");
			db.execSQL("DROP TABLE t_region_temp");
		}
	}

需要注意:

  • 重命名表的SQL格式为ALTER TABLE <oldname> RENAME TO <newname>;
  • 导入新数据的insert into select语句中不能出现values关键字
  • 记得删除临时表

跨越版本的升级

处理好了单个版本的升级,还有一个更加棘手的问题:如果应用程序发布了多个版本,以致出现了三个以上数据库版本, 如何确保所有的用户升级应用后数据库都能用呢?有两种方式:

方式一:确定相邻版本的差别,从版本1开始依次迭代更新,先执行v1到v2,再v2到v3……

方式二:为每个版本确定与现在数据库的差别,为每个case撰写专门的升级代码。

方式一的优点是每次更新数据库的时候只需要在onUpgrade方法的末尾加一段从上个版本升级到新版本的代码,易于理解和维护,缺点是当版本变多之后,多次迭代升级可能需要花费不少时间,增加用户等待;

方式二的优点则是可以保证每个版本的用户都可以在消耗最少的时间升级到最新的数据库而无需做无用的数据多次转存,缺点是强迫开发者记忆所有版本数据库的完整结构,且每次升级时onUpgrade方法都必须全部重写。

以上简单分析了两种方案的优缺点,它们可以说在花费时间上是刚好相反的,至于如何取舍,可能还需要结合具体情况分析。

Android 数据库升级完整解决方案

时间: 2024-10-05 03:28:05

Android 数据库升级完整解决方案的相关文章

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

原始完成于:2015-04-27 19:28:22 提供一种思路,优雅的处理Android数据库升级的问题,直接上代码: 1 package com.example.databaseissuetest; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteOpenHelper; 6 import and

Android 数据库升级解决方案

转自:http://blog.csdn.net/leehong2005/article/details/9128501 请考虑如下情况: 在数据库升级时,不同版本的数据库,他们定义的表结构完全可能是不一样的,比如V1.0的表A有10个column,而在V1.1的表A有12个colum,在升级时,表A增加了两列,此时我们应该怎么做呢. 总体思路 1,将表A重命名,改了A_temp. 2,创建新表A. 3,将表A_temp的数据插入到表A. 下面代码列出了更新表的实现,upgradeTables,给

Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())

数据库版本升级对软件的管理操作. 我们手机经常会收到xxx软件升级什么的提醒,你的软件版本更新,同时你的数据库对应的版本也要相应的更新. 数据库版本更新需要主要的问题: 软件的1.0版本升级到1.1版本时,老的数据不能丢. 那么在1.1版本的程序中就要有地方能够检测出来新的软件版本与老的数据库不兼容,并且能够有办法把1.0软件的数据库升级到1.1软件能够使用的数据库. 换句话说,要在1.0软件的数据库的那个表中增加那个字段,并赋予这个字段默认值. 当然有的时候我们对更新后的 版本并没有什么好感,

Android数据库升级实例

第一部分 Andoird的SQLiteOpenHelper类中有一个onUpgrade方法.帮助文档中只是说当数据库升级时该方法被触发.经过实践,解决了我一连串的疑问: 1. 帮助文档里说的“数据库升级”是指什么? 你开发了一个程序,当前是1.0版本.该程序用到了数据库.到1.1版本时,你在数据库的某个表中增加了一个字段.那么软件1.0版本用的数据库在软件1.1版本就要被升级了. 2. 数据库升级应该注意什么? 软件的1.0版本升级到1.1版本时,老的数据不能丢.那么在1.1版本的程序中就要有地

Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点

以下内容可以作为面试官在面试的时候的问题,感觉比较好,是比较常用的知识点,可以用来考察基础是否扎实. 也可以程序猿学习.开发中的注意点.因为稍微不注意,就有可能导致数据库不能用. DBAdapter.java是一个简单的类,主要用来进行数据库操作. 1 package com.example.test_20131218; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 6

Android 数据库升级

数据库升级:v1.0-v2.1从v1.0升级到v2.01,不走oncreate,走onupdategrade直接安装v2.0,走onCreate; v1.0-v3.0:分三种情况1.v1.0升级到v3.0: 不走onCreate,走onUpgrade2.v2.0升级到v3.0:不走onCreate,走onUpgrade3.直接安装v3.0:走onCreate,不走onUpgradepublic class DbHelper extends SQLiteOpenHelper { // privat

Android数据库升级,数据不丢失解决方案

假设要更新TableC表,建议的做法是: 1) 将TableC重命名为TableC_temp SQL语句可以这样写:ALERT TABLE TableC RENAME TO TableC_temp; 2) 创建新的TableC表 3) 将数据从TableC_temp中插入到TableC表中 SQL语句可以这样写:INSERT INTO TableC (Col1, Col2, Col3) SELECT (Col1, Col2, Col3) FROM TableC_temp; 经过这三步,Table

LitePal——Android数据库框架完整使用手册

LitePal for Android LitePal是一个开源的Android库,使开发人员使用SQLite数据库非常简单.您无需编写任何SQL语句就可以完成大部分数据库操作,包括创建或升级表,增.删.改.查操作,合计函数等.LitePal的设置也很简单,您只许5分钟就可以将其集成到您的项目中. 现在就开始体验吧! 功能 使用对象关系映射(ORM)模式. 几乎零配置(仅有一个配置文件,属性值还非常少). 自动维护所有数据表(例如,创建,更改或删除表). 支持多数据库 封装了多种API,是开发者

android数据库升级的措辞

在基类table增加upgrade操作: public abstract class DbBaseTable { private static final String TAG = "DbBaseTable"; /** * @return the DB table name */ abstract String getName(); /** * Creates the DB table according to the DB scheme * * @param db */ abstra