zoukankan      html  css  js  c++  java
  • Android 数据库升级解决方案

    请考虑如下情况:

    在数据库升级时,不同版本的数据库,他们定义的表结构完全可能是不一样的,比如V1.0的表A有10个column,而在V1.1的表A有12个colum,在升级时,表A增加了两列,此时我们应该怎么做呢。

    总体思路

    1,将表A重命名,改了A_temp。

    2,创建新表A。

    3,将表A_temp的数据插入到表A。

    下面代码列出了更新表的实现,upgradeTables,给定表名,更新的列名,就可以实现数据库表的更新。

    1. /**
    2. * Upgrade tables. In this method, the sequence is:
    3. * <b>
    4. * <p>[1] Rename the specified table as a temporary table.
    5. * <p>[2] Create a new table which name is the specified name.
    6. * <p>[3] Insert data into the new created table, data from the temporary table.
    7. * <p>[4] Drop the temporary table.
    8. * </b>
    9. *
    10. * @param db The database.
    11. * @param tableName The table name.
    12. * @param columns The columns range, format is "ColA, ColB, ColC, ... ColN";
    13. */ 
    14. protected void upgradeTables(SQLiteDatabase db, String tableName, String columns) 
    15.     try 
    16.     { 
    17.         db.beginTransaction(); 
    18.  
    19.         // 1, Rename table. 
    20.         String tempTableName = tableName + "_temp"; 
    21.         String sql = "ALTER TABLE " + tableName +" RENAME TO " + tempTableName; 
    22.         execSQL(db, sql, null); 
    23.  
    24.         // 2, Create table. 
    25.         onCreateTable(db); 
    26.  
    27.         // 3, Load data 
    28.         sql =   "INSERT INTO " + tableName + 
    29.                 " (" + columns + ") " + 
    30.                 " SELECT " + columns + " FROM " + tempTableName; 
    31.  
    32.         execSQL(db, sql, null); 
    33.  
    34.         // 4, Drop the temporary table. 
    35.         execSQL(db, "DROP TABLE IF EXISTS " + tempTableName, null); 
    36.  
    37.         db.setTransactionSuccessful(); 
    38.     } 
    39.     catch (SQLException e) 
    40.     { 
    41.         e.printStackTrace(); 
    42.     } 
    43.     catch (Exception e) 
    44.     { 
    45.         e.printStackTrace(); 
    46.     } 
    47.     finally 
    48.     { 
    49.         db.endTransaction(); 
    50.     } 

    得到数据库表的列名

    我们可以通过SQL表得到表的列名。 这里需要注意的一点,int columnIndex = c.getColumnIndex("name"); 这里根据name去取得index。

    1. protected String[] getColumnNames(SQLiteDatabase db, String tableName) 
    2.     String[] columnNames = null; 
    3.     Cursor c = null; 
    4.  
    5.     try 
    6.     { 
    7.         c = db.rawQuery("PRAGMA table_info(" + tableName + ")", null); 
    8.         if (null != c) 
    9.         { 
    10.             int columnIndex = c.getColumnIndex("name"); 
    11.             if (-1 == columnIndex) 
    12.             { 
    13.                 return null; 
    14.             } 
    15.  
    16.             int index = 0; 
    17.             columnNames = new String[c.getCount()]; 
    18.             for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) 
    19.             { 
    20.                 columnNames[index] = c.getString(columnIndex); 
    21.                 index++; 
    22.             } 
    23.         } 
    24.     } 
    25.     catch (Exception e) 
    26.     { 
    27.         e.printStackTrace(); 
    28.     } 
    29.     finally 
    30.     { 
    31.         closeCursor(c); 
    32.     } 
    33.  
    34.     return columnNames; 

    upgradeTables方法应该是在onUpgrade方法中去调用。

    数据库升级的意义

    在应用程序开发的过程中,数据库的升级是一个很重要的组成部分(如果用到了数据库),因为程序可能会有V1.0,V2.0,当用户安装新版本的程序后,必须要保证用户数据不能丢失,对于数据库设计,如果发生变更(如多添加一张表,表的字段增加或减少等),那么我们必须想好数据库的更新策略。

    1,定义数据库版本

    数据库的版本是一个整型值,在创建SQLiteOpenHelper时,会传入该数据库的版本,如果传入的数据库版本号比数据库文件中存储的版本号大的话,那么SQLiteOpenHelper#onUpgrade()方法就会被调用,我们的升级应该在该方法中完成。

    2,如何写升级逻辑

    假如我们开发的程序已经发布了两个版本:V1.0,V1.2,我们正在开发V1.3。每一版的数据库版本号分别是18,19,20。

    对于这种情况,我们应该如何实现升级?

    用户的选择有:                  

    1) V1.0 -> V1.3  DB 18 -> 20                 

    2) V1.1 -> V1.3  DB 19 -> 20     

    3,注意

    数据库的每一个版本所代表的数据库必须是定义好的,比如说V18的数据库,它可能只有两张表TableA和TableB,如果V19要添加一张表TableC,如果V20要修改TableC,那么每一个版本所对应的数据库结构如下:

    V18  --->  TableA, TableB

    V19  --->  TableA, TableB, TableC

    V20  --->  TableA, TableB, TableC (变更)

    onUpgrade()方法的实现如下:

    1.        // Pattern for upgrade blocks: 
    2. // 
    3. //    if (upgradeVersion == [the DATABASE_VERSION you set] - 1){ 
    4. //        .. your upgrade logic.. 
    5. //        upgradeVersion = [the DATABASE_VERSION you set] 
    6. //    } 
    7.  
    8.  
    9. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
    10.     int upgradeVersion  = oldVersion; 
    11.  
    12.     if (18 == upgradeVersion) { 
    13.         // Create table C 
    14.         String sql = "CREATE TABLE ..."; 
    15.         db.execSQL(sql); 
    16.         upgradeVersion = 19; 
    17.     } 
    18.  
    19.     if (20 == upgradeVersion) { 
    20.         // Modify table C 
    21.         upgradeVersion = 20; 
    22.     } 
    23.  
    24.     if (upgradeVersion != newVersion) { 
    25.         // Drop tables 
    26.         db.execSQL("DROP TABLE IF EXISTS " + tableName); 
    27.         // Create tables 
    28.         onCreate(db); 
    29.     } 
          

    从上面的代码可以看到,我们在onUpgrade()方法中,处理了数据库版本从18 -> 20的升级过程,这样做的话,不论用户从18 -> 20,还是从19 -> 20,最终程序的数据库都能升级到V20所对应的数据库结构。 

    4,如何保证数据不丢失

    这是很重要的一部分,假设要更新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;               

                       经过这三步,TableC就完成了更新,同时,也保留了原来表中的数据。 

    注意:

    在onUpgrade()方法中,删除表时,注意使用事务处理,使得修改能立即反应到数据库文件中。      

    SQL语句

    由于Android是使用开源的SQLite3作为其数据库,所以,我们在开发数据库模块时,一定要注意SQLite3支持哪些关键字,函数等,不是所有的关键字,SQLite都是支持的。

    下面列出了一些参考链接:

    SQLite3官方文档:http://sqlite.org/

    W3CSchool网站:http://www.w3school.com.cn/sql/index.asp/

    SQL语句写得好坏能直接影响到数据库的操作。我曾经就遇到过SQL语句影响查询性能,更新3000条记录,用时30移左右,但在对WHERE条件的字段加上索引后,性能提升到3~4秒。

  • 相关阅读:
    LeetCode Array Easy 414. Third Maximum Number
    LeetCode Linked List Medium 2. Add Two Numbers
    LeetCode Array Easy 283. Move Zeroes
    LeetCode Array Easy 268. Missing Number
    LeetCode Array Easy 219. Contains Duplicate II
    LeetCode Array Easy 217. Contains Duplicate
    LeetCode Array Easy 189. Rotate Array
    LeetCode Array Easy169. Majority Element
    LeetCode Array Medium 11. Container With Most Water
    LeetCode Array Easy 167. Two Sum II
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4445667.html
Copyright © 2011-2022 走看看