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