ndroid SQLite 客户端数据库升级
一,前言
没有采用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() {
@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,tem
p);
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.getInsertConten
t());
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_collecti
on,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. //此时更新数据库版本
温馨提示:答案为网友推荐,仅供参考