之前的文章有提到,可以在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. Disabling default console handler in Java Logger by codes

    The open source packages usu. relies on log4j or Java Logger to print logs, by default the console h ...

  2. 使用Nginx实现负载均衡

    使用Nginx实现负载均衡 一.nginx简介 nginx是一个高性能的HTTP服务器和反向代理服务器.它起初是俄罗斯人Igor Sysoev开发的,至今支撑者俄罗斯的很多大型的网站. 二.nginx ...

  3. 精神哥讲Crash(一):UnsatisfiedLinkError

    版权声明:本文为腾讯Bugly原创文章,如需转载,请标明出处.   大家好,我是腾讯Bugly的精神哥(英文名:spirit),是Bugly资深码奴的同时,又是Bugly神秘的Crash实验室研究员哦 ...

  4. System.load(String filename)和System.loadLibrary(String libname)的区别

    前言 之前一篇文章在写Native方法的时候,第一个步骤里面有这么一段代码 static { System.load("D:" + File.separator + "H ...

  5. 初探ECMAScript6

    基础变化 String类型新增了三个方法,不必使用indexOf来判断一个字符串是否在另一个字符串内 //String changes var a = "Hello world"; ...

  6. openwrt-智能路由器hack技术(2)---"网路信息监控和窃取"

    openwrt-智能路由器hack技术(2)---"网路信息监控和窃取" 1   导读 PS:之前写的一个文章,现在发现结构内容排版不是太好,导致阅读体验太差,影响传播和SEO,所 ...

  7. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...

  8. 修复Telerik reporting 在网页中使用时的样式

    在ASP.NET 网页或ASP MVC中嵌入Telerik Reporting时,报表出来的样式是有问题的,按扭的位置错位了. 在页面中引入以下CSS文件可以将报表样式修复从而回到正常的报表样式. . ...

  9. .NET Framework中重点类型的继承关系

    继承关系 Object ├─Array │ └─T[] ├─ArrayList ├─List<T> └─String 集合类型的接口 下图展示了集合类型的各种接口的相互关系.注意,下图中所 ...

  10. 跟我一起云计算(4)——lucene

    了解lucene的基本概念 这一部分可以参考我以前写的博客: http://www.cnblogs.com/skyme/tag/lucene/ lucene是什么 下图是一个很好的说明: 1.luce ...