在android应用程序需要升级时,如果之前的数据库表结构发生了变化或者新添加了表,就需要对数据库进行升级,并保留原来的数据库数据。

程序如何知道数据库需要升级?

数据库实现方法中有必须继承两个方法:onCreate和onUpgrade,他们的调用过程如下:
1. 如果数据库文件不存在,SQLiteOpenHelper在自动创建数据库后只会调用onCreate方法,在该方法中一般需要创建数据库中的表、视图等组件。在创建之前,数据库是空的,因此,不需要先删除数据库中相关的组件。
2. 如果数据库文件存在,并且当前的版本号高于上次创建或升级时的版本号,SQLiteOpenHelper会调用onUpgrade方法,调用该方法后,会更新数据库版本号。在onUpgrade方法中除了创建表、视图等组件外,还需要首先删除这些相关的组件,因此,在调用onUpgrade方法之前,数据库是存在的,里面还有很多数据库组件。
3. 综合上述两点,可以得出一个结论。如果数据库文件不存在,只有onCreate方法被调用(该方法只会在创建数据库时被调用1次)。如果数据库文件存在,并且当前版本较高,会调用onUpgrade方法来升级数据库,并更新版本号。


SQLiteOpenHelper类的构造函数有一个参数是int version,它的意思就是指数据库版本号。比如在软件1.0版本中,我们使用SQLiteOpenHelper访问数据库时,该参数为1,那么数据库版本号1就会写在我们的数据库中。

到了1.1版本,我们的数据库需要发生变化,那么我们1.1版本的程序中就要使用一个大于1的整数来构造SQLiteOpenHelper类,用于访问新的数据库,比如2。

当我们的1.1新程序读取1.0版本的老数据库时,就发现老数据库里存储的数据库版本是1,而我们新程序访问它时填的版本号为2,系统就知道数据库需要升级。

何时触发数据库升级?如何升级?

当系统在构造SQLiteOpenHelper类的对象时,如果发现版本号不一样,就会自动调用onUpgrade函数,让你在这里对数据库进行升级。根据上述场景,在这个函数中把老版本数据库的相应表中增加字段,并给每条记录增加默认值即可。

新版本号和老版本号都会作为onUpgrade函数的参数传进来,便于开发者知道数据库应该从哪个版本升级到哪个版本。

升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。

下面举例写出具体过程:

如果我上一个版本的数据库表结构没发生变化,但是新增了两张表,而且之前有一张表中默认有4条数据,现在新版本默认有11条数据,那么该怎么操作呢,假设表A发生了变化,并且新建了表B、C

1.首先我们需要把原来的数据库表重命名一下

public static final String TEMP_SQL_CREATE_TABLE_SUBSCRIBE = "alter table "            + A + " rename to temp_A";

原来的表结构是:

private static final String SQL_CREATE_TABLE_SUBSCRIBE = "create table  if not exists "            + A + "(id integer primary key autoincrement,code text not null,name text,username text)";

2.然后把备份表temp_A中的数据copy到新创建的数据库表A中,这个表A没发生结构上的变化

public static final String INSERT_SUBSCRIBE = "select 'insert into A (code,name,username,tablename) 
values ('''||code||''','''||name||''',''cnki'','''||tablename||'''')' as insertSQL from temp_A";

3.此时临时表中的数据已经全部复制到了表A中,但是我之前的表A中有四条默认的数据,用户可能删了,可能又增加了新的数据,那我不管用户什么操作,我都把这4条删除掉,然后重新添加一次,这样就保证了之前的四条数据还在新的数据表中

这是我之前的四条数据,我先找出来:

public static final String[] arrWhereAct = { "where code ='K174' and tablename = 'phonepaper'", "where code ='GMRB' and tablename = 'newspaper'", "where code ='XJSJ' and tablename = 'magazine'", "where code ='JTKL' and tablename = 'magazine'" };

4.删除备份表

public static final String DELETE_TEMP_SUBSCRIBE = "delete from temp_A "; public static final String DROP_TEMP_SUBSCRIBE = "drop table if exists temp_A";

5.然后把数据库版本号改为比之前高的版本号,在OnUpgrade方法中执行上述语句就行,具体如下:

@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { for (int j = oldVersion; j <= newVersion; j++) { switch (j) { case 2:
          //创建临时表
db.execSQL(TEMP_SQL_CREATE_TABLE_SUBSCRIBE);           //执行OnCreate方法,这个方法中放的是表的初始化操作工作,比如创建新表之类的
onCreate(db);           //删除之前的表里面的那4条默认的数据
for (int i = 0; i < arrWhereAct.length; i++) { db.execSQL(DELETE_TEMP_SUBSCRIBE + arrWhereAct[i]); } //将临时表中的数据放入表A
         Cursor cursor
= db.rawQuery(INSERT_SUBSCRIBE, null); if (cursor.moveToFirst()) { do { db.execSQL(cursor.getString(cursor .getColumnIndex("insertSQL"))); } while (cursor.moveToNext()); } cursor.close();           //将临时表删除掉
db.execSQL(DROP_TEMP_SUBSCRIBE);
break; default: break; } } }

为什么要在方法里写for循环,主要是考虑到夸版本升级,比如有的用户一直不升级版本,数据库版本号一直是1,而客户端最新版本其实对应的数据库版本已经是4了,那么我中途可能对数据库做了很多修改,通过这个for循环,可以迭代升级,不会发生错误

参考解决方案:

解决方案:
我们在4月份数据库建立时,使用下面的方式
Java代码
  1. publicclassDatabaseHelperextendsSQLiteOpenHelper{
  2. privatestaticfinalStringDB_NAME="mydata.db";//数据库名称
  3. privatestaticfinalintversion=1;//数据库版本
  4. publicDatabaseHelper(Contextcontext){
  5. super(context,DB_NAME,null,version);
  6. }
  7. @Override
  8. publicvoidonCreate(SQLiteDatabasedb){
  9. Stringsql="createtableuser(idintegerprimarykeyautoincrement,usernamevarchar(20),passwordvarchar(60));";
  10. db.execSQL(sql);
  11. }
  12. @Override
  13. publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
  14. }
  15. }


于是到了五月份,由于业务需要,我们想添加新的字段到这个表里。我们这样写代码:

Java代码
  1. publicclassDatabaseHelperextendsSQLiteOpenHelper{
  2. privatestaticfinalStringDB_NAME="mydata.db";//数据库名称
  3. privatestaticfinalintversion=2;//数据库版本
  4. publicDatabaseHelper(Contextcontext){
  5. super(context,DB_NAME,null,version);
  6. }
  7. @Override
  8. publicvoidonCreate(SQLiteDatabasedb){
  9. Stringsql="createtableuser(idintegerprimarykeyautoincrement,usernamevarchar(20),passwordvarchar(60));";
  10. db.execSQL(sql);
  11. }
  12. @Override
  13. publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
  14. if(oldVersion==1&&newVersion==2){
  15. //从版本1到版本2时,增加了一个字段desc
  16. Stringsql="altertable[user]add[desc]nvarchar(300)";
  17. db.execSQL(sql);
  18. }
  19. }
  20. }


如果数据库结构变化比较大,要做彻底的升级,怎么办?

Java代码
  1. publicclassDatabaseHelperextendsSQLiteOpenHelper{
  2. privatestaticfinalStringDB_NAME="mydata.db";//数据库名称
  3. privatestaticfinalintversion=2;//数据库版本
  4. publicDatabaseHelper(Contextcontext){
  5. super(context,DB_NAME,null,version);
  6. }
  7. @Override
  8. publicvoidonCreate(SQLiteDatabasedb){
  9. Stringsql="createtableuser(idintegerprimarykeyautoincrement,usernamevarchar(20),passwordvarchar(60));";
  10. db.execSQL(sql);
  11. }
  12. @Override
  13. publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
  14. //如果本次升级数据库完全变化很大,需要删除旧版本,建立新版本;
  15. if(oldVersion==1&&newVersion==2){
  16. db.execSQL("droptableuser;");
  17. //自动调用onCreate
  18. }
  19. }
  20. }

具体实现就是这样,望高手吐槽!

更多相关文章

  1. Android系统配置数据库注释(settings.db)
  2. android“设置”里的版本号
  3. Android(安卓)version and Linux Kernel version
  4. opengrok setup on ubuntu for android source code browser
  5. Android——开发环境
  6. android通过ksoap2对webservice的解析
  7. Android如何获得系统版本
  8. Android,一个思路实现APP版本更新
  9. flutter-使用第三方库,编译和运行版本不一致问题 2

随机推荐

  1. ubuntu下编译JNI程序
  2. android中数据库创建操作的模式
  3. 第五课--位置布局
  4. Android漏洞,WebView漏洞,Web漏洞与Web安全
  5. java与VC通信-socket
  6. OSG for Android新手教程系列(四)——JNI与
  7. Android 开发必读:如何成为一名优秀的Andr
  8. 我的android 第27天 - Intent意图
  9. android eclipse集成环境
  10. Android内核驱动——电源管理