之前的文章有提到,可以在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配置信息,应用的数据库信息就创建出来了。

Android数据库表的创建和数据升级操作的更多相关文章

  1. oracle数据库表中,插入数据的时候如何产生一个 字母+数字 编号?

    Oracle 语句中“||”代表什么啊? oracle数据库表中,插入数据的时候如何产生一个 字母+数字 编号? 排序的话,用order by来处理即可.比如:cola123a234b999b335s ...

  2. (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句

    (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 在我们RDIFramework.NET代码生成器中,有这样一个应用,就是通过数据库表自动生成表的CREA ...

  3. 利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句

    利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 在我们RDIFram ...

  4. 修改SQL Server数据库表的创建时间最简单最直接有效的方法

    说明:这篇文章是几年前我发布在网易博客当中的原创文章,但由于网易博客现在要停止运营了,所以我就把这篇文章搬了过来,因为这种操作方式是通用的,即使是对现在最新的SQL Server数据库里面的操作也是一 ...

  5. EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)

    上一篇写了<Entity Farmework领域建模方式 3种编程方式>,现在就Code First 继续学习 1.数据库表的创建 新建一个MVC的项目,在引用右击管理NuGet程序包,点 ...

  6. Android数据库高手秘籍(三)——使用LitePal升级表

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/39151617 在上一篇文章中,我们学习了LitePal的基本使用方法,体验了使用框 ...

  7. 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入

    文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...

  8. oracle数据库表空间创建&导入&导出

    1.表空间创建 --删除表空间 drop tablespace EVPBDMGIS including contents and datafiles; --删除用户 drop user EVPBDMG ...

  9. Oracle数据库——表的创建与管理

    一.涉及内容 1.掌握使用OEM工具创建.修改和删除表. 2.掌握使用SQL语句创建.修改和删除表. 3.掌握使用SQL语句插入.修改和删除数据. 4.理解各种约束的作用,并能够使用OEM工具和SQL ...

随机推荐

  1. [leetcode 27]Implement strStr()

    1 题目: Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if ...

  2. storysnail的Windows串口编程笔记

    storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...

  3. PAT/简单模拟习题集(一)

    B1001.害死人不偿命的(3n+1)猜想 (15) Description: 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉 ...

  4. Python札记 -- 使用easy_install进行模块/包管理

    今天在阅读以前项目代码时,发现里面使用的第三方模块的参数相当诡异,总是对不上.经过分析之后,发现是自己安装的第三方模块跟项目使用的版本不一致.在Python中进行模块/包管理的话,就不得不提到easy ...

  5. 不写1行代码,在Mac上体验ASP.NET 5的最简单方法

    昨天微软发布了ASP.NET 5 beta2(详见ASP.NET 5 Beta2 发布),对ASP.NET 5的好奇心又被激发了. 今天下午在Mac OS X上体验了一下ASP.NET 5,而且借助Y ...

  6. UWP滑动后退

    经过近些年智能手机App的不断发展,用户已经不仅仅满足于功能上的需求.UI.设计等非功能点逐渐在App体验中占了大多数的分数.不知从何时起,滑动手势就成为了App的一个标配.他不仅仅是一个功能,更是一 ...

  7. 解析ASP.NET Mvc开发之EF延迟加载

    目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 ------------------------ ...

  8. 统计第一个空字符前面的字符长度(java实现)

    举例来说:char buf[] = {'a','b','c','d','e','f','\0','x','y','z'}当输入N=10或20,期待输出是6:当输入N=3或5,期待输出是3或5. pac ...

  9. Linux下Java开发环境搭建—CentOS下Eclipse的安装教程

    据了解,在Linux下的Java开发很多时候都比较喜欢使用vim + 插件,反而很少使用Eclipse,但是我是第一次使用Linux来进行Java编程,就什么都体验下啦,好啦,废话不多说,直接开始啦. ...

  10. 图文详解Unity3D中Material的Tiling和Offset是怎么回事

    图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...