• 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秒。

  • 相关阅读:
    Rancher 中 Traefik 负载均衡 Initializing 状态
    【音视频】YUV、RGB视频像素处理
    Debian WSL 2 安装使用 Docker
    CentOS 7 切换 Java 版本到 Java 11
    阿里云 CentOS 8.2 停服后 yum / dnf 无法安装更新
    CentOS 8 Stream 报错处理 Faild to start Load Kernel Modules. Failed to insert 'ipmi_si': No such device
    System.getProperty()获取系统变量
    简单科普私钥、地址、助记词、Keystore的区别
    synchronized实现原理及锁升级过程
    H3C 策略路由原理介绍
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4445667.html
Copyright © 2020-2023  润新知