zoukankan      html  css  js  c++  java
  • Android数据库表的创建和数据升级操作

        之前的文章有提到,可以在xml文件中配置数据库信息:http://www.cnblogs.com/wenjiang/p/4492303.html,现在就讲如何利用这些信息类构建数据库。

        xml文件大概如下:

    <?xml version="1.0" encoding="utf-8"?>
    <database>
        <!-- 数据库名称 -->
        <dbname value="zwb.db"></dbname>
    
        <!-- 数据库版本 -->
        <version value="1"></version>
    
        <!-- 数据库表 -->
        <list>
            <mapping class="com.zwb.args.dbpratice.model.Status"></mapping>
            <mapping class="com.zwb.args.dbpratice.model.User"></mapping>
        </list>
    </database>

        读取出来的信息其实很简单:数据库名字,数据库版本和数据库表。

        Android原本就提供了SQLiteOpenHelper来帮助我们完成数据库的一些基本操作,所以这里还是需要实现SQLiteOpenHelper的。

        定义一个SQLiteOpenHelper,在初始化的时候将数据库名字和数据库版本传进去:

     public BaseSQLiteOpenHelper(Context context, String name, int version) {
        super(context, name, null, version);
    }

         接下来就是在onCreate方法中实现创建表的动作:

         考虑到数据升级的问题,我将有关数据升级的操作都放在一个方法中,然后在onUpgrade方法中调用onCreate就行了。

         这里只考虑数据升级的问题,当然,降级也是可以的,不过一般这种情况在移动端比较少见。

         之前将包含数据库的表名的List存储进SharedPreferencesManager中,当然,一般的SharedPreferencesManager是不能存储容器类的,但这里我进行了扩展,具体的实现后面有需要再拿出来。

         数据库是在xml文件中配置数据库表的信息,所以必须判断从xml文件中读取出来的数据库信息是否还是和之前一致,如果原先的配置信息没有的话,就要创建表(哪怕只是修改表名,都当做是重新创建表,这是无可置疑的,因为修改旧表后还指望能够将数据迁移到新表中,说明一开始建表时候实在是太草率了。。。),如果原先的配置有,现在没有,说明是要删除旧表。

    List<String> oldTableList = SharedPreferencesManager.getInstance().getListString("tables");
    if (oldTableList.size() != 0) {
    
         for (String table : oldTableList) {
              if (!DatabaseCache.tableSet.contains(table)) {
                    dropTable(db, table);
              }
         }
    
         for (String table : DatabaseCache.tableSet) {
               if (!oldTableList.contains(table)) {
                    createTable(db, table);
               }
          }
    }

          dropTable的实现非常简单:

     String deleteSql = "drop table if exists " + table;
     db.execSQL(deleteSql);

          createTable的实现也不复杂,同样是拼接SQL语句:

        private void createTable(SQLiteDatabase db, String table) {
            try {
                StringBuilder sql = new StringBuilder("create table if not exists ");
                BaseTable entity = (BaseTable) (Class.forName(table).newInstance());
                String tableName = getTableName(entity);
                sql.append(tableName);
                sql.append(" (id integer primary key autoincrement, ");
                List<String> columnList = getColumns(entity);
                for (int i = 0, length = columnList.size(); i < length; i++) {
                    sql.append(columnList.get(i) + " ");
                    if (i == length - 1) {
                        break;
                    }
                    sql.append(", ");
                }
                sql.append(");");
                db.execSQL(sql.toString());
            } catch (InstantiationException e) {
                LogUtil.e(e.toString());
            } catch (IllegalAccessException e) {
                LogUtil.e(e.toString());
            } catch (ClassNotFoundException e) {
                LogUtil.e(e.toString());
            } catch (NoSuchTableException e) {
                LogUtil.e(e.toString());
            }
        }

           Android本身也提供了对SQL语句的封装,但实际上,使用Android的API还是不如自己写SQL。。。

           如果应用是第一次安装,那么数据库的创建动作就结束了,最后只要将新的配置信息存储到SharedPreferencesManager中就行。

           但如果是数据库升级,在执行完上面的操作,表是该删的删,该建的的建,但如果要做数据迁移,比如说,某张表增加了一些字段(这里不做删除字段的处理,就算有多余字段的数据保留也并不是个问题,比起丢失数据的严重性来说,一定程度的冗余字段还是可以接受的)。

           实现也是比较简单,就是几个步骤:将旧表重命名为一个临时表保存数据,创建旧表,将临时表的数据迁移到旧表中,删除临时表,每个步骤都是SQL语句的拼接而已:

           for (String tableEntity : DatabaseCache.tableSet) {
                try {
                    BaseTable entity = (BaseTable) (Class.forName(tableEntity).newInstance());
                    db.beginTransaction();
                    String table = getTableName(entity);
                    String selectSql = "select * from " + table;
                    Cursor cursor = db.rawQuery(selectSql, null);
                    List<String> oldColumns = new ArrayList<>();
                    for (String column : cursor.getColumnNames()) {
                        oldColumns.add(column);
                    }
                    String alterSql = "alter table " + table + " rename to " + table + "_temp";
                    db.execSQL(alterSql);
    
                    createTable(db, tableEntity);
    
                    List<String> newColumns = getColumnFrom(tableEntity);
                    StringBuilder upgradeSqlBuilder = new StringBuilder("insert into " + table + " select id, ");
                    int i = 0;
                    for (String column : newColumns) {
                        if (oldColumns.contains(column)) {
                            upgradeSqlBuilder.append(column + ", ");
                            i++;
                        }
                    }
    
                    if ((i != 0) && (i < newColumns.size())) {
                        for (int j = 0, length = newColumns.size() - i; j < length; j++) {
                            upgradeSqlBuilder.append("'', ");
                        }
                    }
    
                    String upgradeStr = upgradeSqlBuilder.toString();
                    String upgradeSql = upgradeStr.substring(0, upgradeStr.length() - 2) + " from " + table + "_temp";
                    db.execSQL(upgradeSql);
                    dropTable(db, table + "_temp");
                    db.setTransactionSuccessful();
                    db.endTransaction();
                } catch (InstantiationException e) {
                    LogUtil.e(e.toString());
                } catch (IllegalAccessException e) {
                    LogUtil.e(e.toString());
                } catch (ClassNotFoundException e) {
                    LogUtil.e(e.toString());
                } catch (NoSuchTableException e) {
                    LogUtil.e(e.toString());
                }
            }

          由于涉及到的数据库操作比较多,我就将这些操作放在事务中执行。

          到了这里,根据读取的xml配置信息,应用的数据库信息就创建出来了。

        

  • 相关阅读:
    Ext.net中Combobox如何绑定数据库中的值-通用方法
    Tree通用的系列方法列表-treepanel
    这个时代“寒门再难出贵子” (转帖)
    java 文件保存到本地
    bootsrap的font awesome的各种图标,包括动画图标
    去除html的&nbsp;标签
    Java从网络读取图片并保存至本地
    java正则表达式获得html字符串中<img src>的src中的url地址
    解决IDEA自动重置LanguageLevel和JavaCompiler版本的问题
    JAVA-JSP内置对象之page对象调用Servlet
  • 原文地址:https://www.cnblogs.com/wenjiang/p/4557196.html
Copyright © 2011-2022 走看看