zoukankan      html  css  js  c++  java
  • Android客户端SQLite数据库升级方案

    转载:http://lagunarock.iteye.com/blog/1729582

    一,前言

    没有采用Android自身提供的那一套数据库操作方式。而是想对SQLite数据库文件有更全面的控制,包括随时导出数据库文件修改表结构,增删数据等等。这样一来虽然在开放中得到不少便利,但是也带来了数据库升级的一些问题。

    后来不得已采用了一种方案,可以解决问题,现将方案的全部实现细节记录下来。最后也会提出一些我认为有问题的地方。

    二,数据库文件拷贝

    程序不负责数据库的创建,SQLite数据库文件是在外部创建好的。程序启动阶段拷贝进SD卡。以达到对数据库结构的全面控制。

    数据库文件存放位置见附件图片。

    Java代码  收藏代码
    1. public void copyDBFile() {  
    2.         // 数据库路径  
    3.         if (!FileOperator.checkFile(SysConst.DB_PATH)) {  
    4.             boolean result = FileOperator.write2Sdcard(activity,  
    5.                     R.raw.scpip_collection, SysConst.DB_PATH);  
    6.             Debug.log("无数据库文件,首次拷贝" + result);  
    7.             if (!result) {  
    8.                 throw new IllegalAccessError(activity  
    9.                         .getString(R.string.copy_db_exception));  
    10.             } else {  
    11.                 // 拷贝成功,更新数据库版本  
    12.                 try {  
    13.                     PackageInfo info = activity.getPackageManager()  
    14.                             .getPackageInfo(activity.getPackageName(), 0);  
    15.                     // 当前程序版本号,在AndroidManifest.xml中定义  
    16.                     int versionCode = info.versionCode;  
    17.                     Config.saveDbVer(versionCode);  
    18.                     Debug.log("拷贝成功" + result);  
    19.                 } catch (NameNotFoundException e) {  
    20.                     Debug.e(e);  
    21.                 }  
    22.             }  
    23.         } else {  
    24.             // 数据库已存在的情况  
    25.             if (dbUpdate.needUpdate() ) {  
    26.                 activity.showProgress("数据库升级中,请稍后", false);  
    27.                 new Thread() {  
    28.                     @Override  
    29.                     public void run() {  
    30.                         try {  
    31.                             Debug.log("update db");  
    32.                             dbUpdate.updateDb();  
    33.                             handler.sendEmptyMessage(0);  
    34.                         } catch (Exception e) {  
    35.                             Debug.e(e);  
    36.                             handler.sendEmptyMessage(-1);  
    37.                         }  
    38.                     };  
    39.                 }.start();  
    40.             }  
    41.         }  
    42.     }  

     其中有几个要点:

    1、检测数据库文件是否已经存在。不存在则从raw文件夹复制数据库文件拷贝至SD卡中指定目录。

    2、数据库版本是根据应用的versionCode相同。拷贝数据库后,会把当前versionCode写入数据库的表中。

    Xml代码  收藏代码
    1. <manifest   
    2.     xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     package="com.xxx"   
    4.     android:versionCode="2"  
    5.     android:versionName="1.01.001">  
    6.     <uses-sdk android:minSdkVersion="8" />  

     versionCode在AndroidManifest.xml文件中。

    在这种方案下,实际上是由versionCode控制数据库版本,versionName控制程序版本。

    3、SD卡指定目录已经存在数据库文件的情况,则读取其中保存的数据库版本号,与versionCode对比,从而确定是否需要升级数据库。代码如下:

    Java代码  收藏代码
    1. public boolean needUpdate() {  
    2.         int currVer = Config.getDbVer();  
    3.         return currVer < getAppVersion();  
    4.     }  
    5.       
    6.     public int getAppVersion(){  
    7.         try {  
    8.             PackageInfo info = context.getPackageManager().getPackageInfo(  
    9.                     context.getPackageName(), 0);  
    10.             // 当前程序版本号,在AndroidManifest.xml中定义  
    11.             return info.versionCode;  
    12.         } catch (NameNotFoundException e) {  
    13.             Debug.e(e);  
    14.             return 1;  
    15.         }  
    16.     }  

    三,升级数据库

    包括三个步骤:

    1、从程序中拷贝新数据库文件至SD卡指定目录,命名为temp.db。

    Java代码  收藏代码
    1. String temp = SysConst.DB_FOLDER + "temp.db";  
    2. boolean s1 = FileOperator.write2Sdcard(context, R.raw.scpip_collection,temp);  

    2、分别获取两个数据源。

    Java代码  收藏代码
    1. //原数据库文件  
    2. BaseDao sd = new BaseDao();  
    3. //新数据库文件  
    4. BaseDao nd = new BaseDao(temp);  

     对于SQLite数据库来讲,数据源就是数据库文件。BaseDao是自己封装的,关键在于要可以配置不同的数据源

    具体实现的相关代码如下:

    Java代码  收藏代码
    1. private String dbPath;  
    2.   
    3. public BaseDao() {}  
    4.   
    5. public BaseDao(String dbPath) {  
    6.     this.dbPath = dbPath;  
    7. }  
    8.   
    9. ublic SQLiteDatabase getDb() {  
    10.     return SQLiteDatabase.openDatabase(SysConst.DB_PATH, null,  
    11.             SQLiteDatabase.OPEN_READWRITE);  
    12. }  
    13.   
    14. public SQLiteDatabase getDb(String dbPath) {  
    15.     return SQLiteDatabase.openDatabase(dbPath, null,  
    16.             SQLiteDatabase.OPEN_READWRITE);  
    17. }  

    这样就可以根据文件,获取不同的SQLiteDatabase 对象。

    3、传输数据

    把原数据库中的数据查询出来,插入到新数据库中。

    Java代码  收藏代码
    1. public <E>void transfer(BaseDao sd,BaseDao nd,Class<E> cls) throws Exception{  
    2.     List<E> list = sd.find(cls, null);  
    3.     nd.batchInsert(list);  
    4. }  

    这里有两个要点,

    第一,使用了自行封装的ORM。

    第二,使用了SQLite批量插入,增加写入效率。代码如下:

    Java代码  收藏代码
    1. @Override  
    2.     public <T> void batchInsert(List<T> datas) throws Exception {  
    3.         SQLiteDatabase dba = null;  
    4.         if(dbPath == null){  
    5.             dba = getDb();  
    6.         } else {  
    7.             dba = getDb(dbPath);  
    8.         }  
    9.         int size = datas.size();  
    10.         try {  
    11.             dba.beginTransaction();  
    12.             for (int i = 0; i < size; i++) {  
    13.                 DaoHelper helper = new DaoHelper(datas.get(i));  
    14.                 String tableName = helper.getTableName();  
    15.                 String sql = "select 1 from " + tableName + " where "  
    16.                         + helper.getPkCol() + "=";  
    17.                 Object id = helper.getPkValue();  
    18.                 if (id instanceof String) {  
    19.                     sql = sql + "'" + id + "'";  
    20.                 } else {  
    21.                     sql = sql + id;  
    22.                 }  
    23.                 c = dba.rawQuery(sql, null);  
    24.                 if (c != null ? (c.getCount() == 1) : false) {  
    25.                     c.close();  
    26.                     continue;  
    27.                 }  
    28.                 if(c != null){  
    29.                     c.close();  
    30.                 }  
    31. //              SqlArgs sa = helper.prepareInsert();  
    32. //              dba.execSQL(sa.getSql(), sa.getArgs());  
    33.                 dba.insert(helper.getTableName(), "", helper.getInsertContent());  
    34.             }  
    35.             dba.setTransactionSuccessful();  
    36.             dba.endTransaction();  
    37.         } finally {  
    38.             dba.close();  
    39.         }  
    40.     }  

    4、写入当前数据库版本,即从程序获得的versionCode。

    5、删除原数据库文件,重命名temp.db。

    完整过程如下:

    Java代码  收藏代码
    1. public void updateDb() throws Exception {  
    2.         //1,写入新的数据库文件,命名为temp  
    3.         String temp = SysConst.DB_FOLDER + "temp.db";  
    4.         boolean s1 = FileOperator.write2Sdcard(context, R.raw.scpip_collection,temp);  
    5.         Debug.log("s1:" + s1);  
    6.         if(s1) {  
    7.             //原数据库文件  
    8.             BaseDao sd = new BaseDao();  
    9.             //新数据库文件  
    10.             BaseDao nd = new BaseDao(temp);  
    11.             //转移数据  
    12.             //此处代码略   
    13.             //删除原数据库文件,重命名临时数据库文件  
    14.             if(FileOperator.delSdcardFile(SysConst.DB_PATH)){  
    15.                 File file = new File(temp);  
    16.                 file.renameTo(new File(SysConst.DB_PATH));  
    17.                             }  
    18.                     //此时更新数据库版本  
    19.             Config.saveDbVer(getAppVersion());  
    20.         }  
    21.     }  

     至此,整个数据库升级完成。在保留原数据的基础上,获取了新的数据库结构。

    四,问题

    1,需要保留的原数据与新表结构不符。这个可以在程序中控制,创建新的OR映射。

    2,效率问题,如果需要保留的数据量非常大的情况下,是否会出现问题。这个是亟待解决的,目前我还没有想到解决办法。

    五,总结

    这个方案针对的情况是外部创建数据库文件,程序启动时从apk包将数据库文件拷贝进SD卡,从而达到对数据库文件的完全控制。

    方案步骤:

    1,检测是否需要升级数据库文件。数据库文件版本是由versionCode控制。程序升级时,如果需要升级数据库,则要将versionCode+1。

    2,将新数据库文件(存在于apk中),写入SD卡。

    3,转移数据。

    4,删除原数据库文件,重命名新数据库文件。

    5,向新数据库写入当前数据库版本。

  • 相关阅读:
    callAfter 例子2
    wxpython
    python 处理excel 进程无法退出的问题
    常用电子技术网
    Emeditor 与正则表达式
    Windows程序中的字符编码
    Delphi7 无法启动 问题搞定
    2007中国发烧盘点之作《天路》发烧女声版
    一台电脑安装多个(虚拟)网卡问题
    无法删除xxx文档/文件夹:找不到指定的路径。请确定指定的路径是否正确
  • 原文地址:https://www.cnblogs.com/tmlee/p/5019208.html
Copyright © 2011-2022 走看看