码迷,mamicode.com
首页 > 移动开发 > 详细

android数据库版本升级总结

时间:2015-06-16 22:34:20      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

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

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

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

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

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

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

表操作用法:

情况一:遇到减少字段的情况,也可以通过创建临时表的方式来实现。
只能在表的末尾添加字段,比如,为 Subscription添加两个字段:
1: ALTER TABLE Subscription ADD COLUMN Activation BLOB;
2 :ALTER TABLE Subscription ADD COLUMN Key BLOB;

情况二:遇到复杂的修改操作,比如在修改的同时,需要进行数据的转移,那么可以采取在一个事务中执行如下语句来实现修改表的需求。
 1. 将表名改为临时表
         ALTER TABLE Subscription RENAME TO __temp__Subscription;

 2. 创建新表
        CREATE TABLE Subscription (OrderId VARCHAR(32) PRIMARY KEY ,UserName VARCHAR(32) NOT NULL ,ProductId VARCHAR(16) NOT NULL);
  
   3. 导入数据  
         INSERT INTO Subscription SELECT OrderId, “”, ProductId FROM __temp__Subscription;
  或者  
        INSERT INTO Subscription() SELECT OrderId, “”, ProductId FROM __temp__Subscription;
  * 注意 双引号”” 是用来补充原来不存在的数据的
  
   4. 删除临时表  
        DROP TABLE __temp__Subscription;

下面举例写出具体过程:

如果我上一个版本的数据库表结构没发生变化,但是新增了两张表,而且之前有一张表中默认有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方法中执行上述语句就行,具体如下:
  1. @Override
  2. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  3. for (int j = oldVersion; j <= newVersion; j++) {
  4. switch (j) {
  5. case 2:
  6.           //创建临时表
  7. db.execSQL(TEMP_SQL_CREATE_TABLE_SUBSCRIBE);
  8.           //执行OnCreate方法,这个方法中放的是表的初始化操作工作,比如创建新表之类的
  9. onCreate(db);
  10.           //删除之前的表里面的那4条默认的数据
  11. for (int i = 0; i < arrWhereAct.length; i++) {
  12. db.execSQL(DELETE_TEMP_SUBSCRIBE + arrWhereAct[i]);
  13. }
  14. //将临时表中的数据放入表A
  15.          Cursor cursor = db.rawQuery(INSERT_SUBSCRIBE, null);
  16. if (cursor.moveToFirst()) {
  17. do {
  18. db.execSQL(cursor.getString(cursor
  19. .getColumnIndex("insertSQL")));
  20. } while (cursor.moveToNext());
  21. }
  22. cursor.close();
  23.       //将临时表删除掉
  24. db.execSQL(DROP_TEMP_SUBSCRIBE);
  25. break;
  26. default:
  27. break;
  28. }
  29. }
  30. }
为什么要在方法里写for循环,主要是考虑到夸版本升级,比如有的用户一直不升级版本,数据库版本号一直是1,而客户端最新版本其实对应的数据库版本已经是4了,那么我中途可能对数据库做了很多修改,通过这个for循环,可以迭代升级,不会发生错误。

项目实践:
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import android.content.Context;
  4. import android.database.Cursor;
  5. import android.database.sqlite.SQLiteDatabase;
  6. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  7. import android.database.sqlite.SQLiteOpenHelper;
  8. import android.util.Log;

  9. /**
  10. * @description:数据库帮助类
  11. * @author samy
  12. * @date 2015年6月16日 下午8:41:18
  13. */
  14. public class DBHelper extends SQLiteOpenHelper {
  15. public static final String NAME = Constant.DATABASE_NAME; // DB name
  16. public static final List<DBUpdateListener> mUpdateList = new ArrayList<DBUpdateListener>();
  17. public DBHelper(Context context) {
  18. // super(context, NAME, null, Constant.DATABASE_VERSION);
  19. super(context, NAME, null, 133);
  20. // version 187:新增tips表和app_recommend表
  21. // version 188:新增matchsync表
  22. // version 189:新增widget_status表
  23. }
  24. public DBHelper(Context context, String name, CursorFactory factory, int version) {
  25. super(context, name, factory, version);
  26. }
  27. /**
  28. * 用户第一次使用软件时调用的操作,用于获取数据库创建语句(SW),然后创建数据库
  29. */
  30. @Override
  31. public void onCreate(SQLiteDatabase db) {
  32. IMDebug.print("创建--会员版--数据库!!!");
  33. db.execSQL(BaseModelTool.getCreateTableSql(UserInfo.class));
  34. db.execSQL(BaseModelTool.getCreateTableSql(ShopIndustry.class)); // 行业
  35. /** V2.0.0版本的数据库变更,增加最后一次聊天的表 */
  36. db.execSQL(BaseModelTool.getCreateTableSql(GroupAssistantStatisticModel.class));
  37. }
  38. /**
  39. * 数据库更新,如果数据库有更新,那么调用BaseModelTool.getAlterTableSql((Class<?> modelType, String string);方法向表中添加相应新字段
  40. */
  41. @Override
  42. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  43. int tempVersion = oldVersion;
  44. addDBUpdateListener();
  45. for (int i = 0; i < mUpdateList.size(); i++) {
  46. if (mUpdateList.get(i).getmPreVersionNo() >= tempVersion) {
  47. mUpdateList.get(i).onUpgrade(db, tempVersion, newVersion);
  48. tempVersion = mUpdateList.get(i).getmCurrVersionNo();
  49. }
  50. }
  51. mUpdateList.clear();
  52. }
  53. private void addDBUpdateListener() {
  54. // v1.5.7 --> v2.0.0 个人信息里面惠信余额和银行卡数的添加
  55. mUpdateList.add(new DBUpdate_V131_V132());
  56. }
  57. /**
  58. * @description:观察者模式 IM数据库:v1.5.7 --> v2.0.0
  59. * @author samy
  60. * @date 2015年6月16日 下午8:39:43
  61. */
  62. private class DBUpdate_V131_V132 extends DBUpdateListener {
  63. public DBUpdate_V131_V132() {
  64. setmPreVersionNo(132);
  65. setmCurrVersionNo(133);
  66. }
  67. @Override
  68. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  69. String sql="";
  70. if (!checkColumnExist(db, "userInfo", "earnings")) {
  71. sql = "alter table userInfo add earnings text;";
  72. }
  73. if (!checkColumnExist(db, "userInfo", "accountbalance")) {
  74. sql = "alter table userInfo add accountbalance text;";
  75. }
  76. if (!checkColumnExist(db, "userInfo", "bankcardnum")) {
  77. sql = "alter table userInfo add bankcardnum text;";
  78. }
  79. db.execSQL(sql);
  80. db.execSQL(BaseModelTool.getDropTableSql(IMGroupRelation.class));
  81. }
  82. }
  83. /**
  84. * @description:判断字段是否在这个表中存在,对字段进行处理时要记得先判断
  85. * @author samy
  86. * @date 2015年6月16日 下午8:36:39
  87. */
  88. private boolean checkColumnExist(SQLiteDatabase db, String tableName, String columnName) {
  89. boolean result = false;
  90. Cursor cursor = null;
  91. try {
  92. cursor = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null);// 查询一行
  93. result = cursor != null && cursor.getColumnIndex(columnName) != -1;
  94. }
  95. catch (Exception e) {
  96. Log.e("SQL", "checkColumnExists..." + e.getMessage());
  97. }
  98. finally {
  99. if (null != cursor && !cursor.isClosed()) {
  100. cursor.close();
  101. }
  102. }
  103. return result;
  104. }
  105. /**
  106. * @description:判断表是否存在
  107. * @author samy
  108. * @date 2015年6月16日 下午8:36:19
  109. */
  110. public boolean tabbleIsExist(SQLiteDatabase db, String tableName) {
  111. boolean result = false;
  112. if (tableName == null) { return false; }
  113. Cursor cursor = null;
  114. try {
  115. db = this.getReadableDatabase();
  116. String sql = "select count(*) from sqlite_master where type =‘table‘ and name =‘" + tableName.trim() + "‘ ";
  117. cursor = db.rawQuery(sql, null);
  118. if (cursor.moveToNext()) {
  119. int count = cursor.getInt(0);
  120. if (count > 0) {
  121. result = true;
  122. }
  123. }
  124. }
  125. catch (Exception e) {
  126. // TODO: handle exception
  127. }
  128. finally {
  129. if (null != cursor && !cursor.isClosed()) {
  130. cursor.close();
  131. }
  132. }
  133. return result;
  134. }
  135. private abstract class DBUpdateListener {
  136. private int mPreVersionNo;
  137. private int mCurrVersionNo;
  138. public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
  139. @SuppressWarnings("unused")
  140. public int getmCurrVersionNo() {
  141. return mCurrVersionNo;
  142. }
  143. protected void setmCurrVersionNo(int mCurrVersionNo) {
  144. this.mCurrVersionNo = mCurrVersionNo;
  145. }
  146. @SuppressWarnings("unused")
  147. public int getmPreVersionNo() {
  148. return mPreVersionNo;
  149. }
  150. protected void setmPreVersionNo(int mPreVersionNo) {
  151. this.mPreVersionNo = mPreVersionNo;
  152. }
  153. }
  154. }
  1. /**各个环境对应不同的环境数据库名称,避免数据db冲突*/
  2. public static final String ENVIRONMENT_FLAG = getEnvironmentFlag();
  3. private static final String getEnvironmentFlag() {
  4. if (Configuration.IS_RELEASE_ENVIRONMENT) {
  5. return "";
  6. } else {
  7. if (Configuration.IS_RELEASE_TEST_ENVIRONMENT) {
  8. return "_release_test";
  9. } else {
  10. return "_test";
  11. }
  12. }
  13. }
  14. /** 数据库的名称 **/
  15. public static final String DATABASE_NAME = getDatabaseName();
  16. private static final String getDatabaseName() {
  17. return "member" + ENVIRONMENT_FLAG + ".db";
  18. }

android数据库版本升级总结

标签:

原文地址:http://www.cnblogs.com/hongfeiliuxing/p/4581776.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!