android开发之sqlite数据库升级

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/39151617

在上一篇文章中,我们学习了LitePal的基本用法,体验了使用框架来进行创建表操作的便利。然而大家都知道,创建表只是数据库操作中最基本的一步而已,我们在一开始创建的表结构,随着需求的变更,到了后期是极有可能需要修改的。因此,升级表的操作对于任何一个项目也是至关重要的,那么今天我们就一起来学习一下,在Android传统开发当中升级表的方式,以及使用LitePal来进行升级表操作的用法。如果你还没有看过前一篇文章,建议先去参考一下 Android数据库高手秘籍(二)——创建表和LitePal的基本用法 。

传统的升级表方式

上一篇文章中我们借助MySQLiteHelper已经创建好了news这张表,这也是demo.db这个数据库的第一个版本。然而,现在需求发生了变更,我们的软件除了能看新闻之外,还应该允许用户评论,所以这时就需要对数据库进行升级,添加一个comment表。

该怎么做呢?添加一个comment表的建表语句,然后在onCreate()方法中去执行它?没错,这样的话,两张表就会同时创建了,代码如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MySQLiteHelper extends SQLiteOpenHelper {  
  2.       
  3.     public static final String CREATE_NEWS = "create table news ("  
  4.             + "id integer primary key autoincrement, "  
  5.             + "title text, "  
  6.             + "content text, "  
  7.             + "publishdate integer,"  
  8.             + "commentcount integer)";  
  9.       
  10.     public static final String CREATE_COMMENT = "create table comment ("  
  11.             + "id integer primary key autoincrement, "  
  12.             + "content text)";  
  13.   
  14.     public MySQLiteHelper(Context context, String name, CursorFactory factory,  
  15.             int version) {  
  16.         super(context, name, factory, version);  
  17.     }  
  18.   
  19.     @Override  
  20.     public void onCreate(SQLiteDatabase db) {  
  21.         db.execSQL(CREATE_NEWS);  
  22.         db.execSQL(CREATE_COMMENT);  
  23.     }  
  24.   
  25.     @Override  
  26.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  27.     }  
  28.   
  29. }  
这对于第一次安装我们软件的用户来说是完全可以正常工作的,但是如果有的用户已经安装过上一版的软件,那么很遗憾,comment表是创建不出来的,因为之前数据库就已经创建过了,onCreate()方法是不会重新执行的。

对于这种情况我们就要用升级的方式来解决了,看到MySQLiteHelper构造方法中的第四个参数了吗,这个就是数据库版本号的标识,每当版本号增加的时候就会调用onUpgrade()方法,我们只需要在这里处理升级表的操作就行了。比较简单粗暴的方式是将数据库中现有的所有表都删除掉,然后重新创建,代码如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MySQLiteHelper extends SQLiteOpenHelper {  
  2.       
  3.     ......  
  4.   
  5.     @Override  
  6.     public void onCreate(SQLiteDatabase db) {  
  7.         db.execSQL(CREATE_NEWS);  
  8.         db.execSQL(CREATE_COMMENT);  
  9.     }  
  10.   
  11.     @Override  
  12.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  13.         db.execSQL("drop table if exists news");  
  14.         onCreate(db);  
  15.     }  
  16.   
  17. }  
可以看到,当数据库升级的时候,我们先把news表删除掉,然后重新执行了一次onCreate()方法,这样就保证数据库中的表都是最新的了。

但是,如果news表中本来已经有数据了,使用这种方式升级的话,就会导致表中的数据全部丢失,所以这并不是一种值得推荐的升级方法。那么更好的升级方法是什么样的呢?这就稍微有些复杂了,需要在onUpgrade()方法中根据版本号加入具体的升级逻辑,我们来试试来吧。比如之前的数据库版本号是1,那么在onUpgrade()方法中就可以这样写:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MySQLiteHelper extends SQLiteOpenHelper {  
  2.   
  3.     ......  
  4.   
  5.     @Override  
  6.     public void onCreate(SQLiteDatabase db) {  
  7.         db.execSQL(CREATE_NEWS);  
  8.         db.execSQL(CREATE_COMMENT);  
  9.     }  
  10.   
  11.     @Override  
  12.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  13.         switch (oldVersion) {  
  14.         case 1:  
  15.             db.execSQL(CREATE_COMMENT);  
  16.         default:  
  17.         }  
  18.     }  
  19.   
  20. }  
可以看到,这里在onUpgrade()方法中加入了一个switch判断,如果oldVersion等于1,就再创建一个comment表。现在只需要调用如下代码,表就可以得到创建或升级了:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SQLiteOpenHelper dbHelper = new MySQLiteHelper(this"demo.db"null2);  
  2. SQLiteDatabase db = dbHelper.getWritableDatabase();  
这里我们将版本号加1,如果用户是从旧版本升级过来的,就会新增一个comment表,而如果用户是直接安装的新版本,就会在onCreate()方法中把两个表一起创建了。

OK,现在软件的第二版本也发布出去了,可是就在发布不久之后,突然发现comment表中少了一个字段,我们并没有记录评论发布的时间。没办法,只好在第三版中修复这个问题了,那我们该怎么样去添加这个字段呢?主要需要修改comment表的建表语句,以及onUpgrade()方法中的逻辑,代码如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MySQLiteHelper extends SQLiteOpenHelper {  
  2.   
  3.     ......  
  4.   
  5.     public static final String CREATE_COMMENT = "create table comment ("  
  6.             + "id integer primary key autoincrement, "   
  7.             + "content text, "   
  8.             + "publishdate integer)";  
  9.   
  10.     ......  
  11.   
  12.     @Override  
  13.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  14.         switch (oldVersion) {  
  15.         case 1:  
  16.             db.execSQL(CREATE_COMMENT);  
  17.         case 2:  
  18.             db.execSQL("alter table comment add column publishdate integer");  
  19.         default:  
  20.         }  
  21.     }  
  22.   
  23. }  
可以看到,在建表语句当中我们新增了publishdate这一列,这样当执行onCreate()方法去创建表的时候,comment表中就会有这一列了。那么如果是从旧版本升级过来的呢?也没有问题,我们在onUpgrade()方法中已经把升级逻辑都处理好了,当oldVersion等于2的时候,会执行alter语句来添加publishdate这一列。现在调用以下代码来创建或升级数据库:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SQLiteOpenHelper dbHelper = new MySQLiteHelper(this"demo.db"null3);  
  2. SQLiteDatabase db = dbHelper.getWritableDatabase();  
将数据库版本号设置成3,这样就可以保证数据库中的表又是最新的了。

这里我们要注意一个细节,switch中每一个case的最后都是没有使用break的,为什么要这么做呢?这是为了保证在跨版本升级的时候,每一次的数据库修改都能被全部执行到。比如用户当前是从第二版程序升级到第三版程序的,那么case 2中的逻辑就会执行。而如果用户是直接从第一版程序升级到第三版程序的,那么case 1和case 2中的逻辑都会执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据也完全不会丢失了。

现在我们已经学习了新增表和新增列这两种升级方式,那么如果是某张表中的某一列已经没有用了,我想把这一列删除掉该怎么写呢?很遗憾,SQLite并不支持删除列的功能,对于这情况,多数软件采取的作法是无视它,反正以后也用不到它了,留着也占不了什么空间,所以针对于这种需求,确实没什么简单的解决办法。

这大概就是传统开发当中升级数据库表的方式了,虽说能写出这样的代码表示你已经对数据库的升级操作理解的比较清楚了,但随着版本越来越多,onUpgrade()方法中的逻辑也会变得愈发复杂,稍微一不留神,也许就会产生错误。因此,如果能让代码自动控制升级逻辑,而不是由人工来管理,那就是再好不过了,那么下面我们就来学习一下怎样使用LitePal来进行升级表的操作。

使用LitePal升级表

通过上一篇文章的学习,我们已经知道LitePal是一款ORM模式的框架了,已经熟悉创建表流程的你,相信对于升级表也一定会轻车熟路的。那么为了模仿传统升级表方式中的需求,现在我们也需要创建一张comment表。第一步该怎么办呢?相信你也许早就已经猜到了,那当然是先创建一个Comment类了,如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.databasetest.model;  
  2.   
  3. public class Comment {  
  4.       
  5.     private int id;  
  6.       
  7.     private String content;  
  8.       
  9.     // 自动生成get、set方法   
  10.     ...  
  11. }  
OK,Comment类中有id和content这两个字段,也就意味着comment表中会有id和content这两列。

接着修改litepal.xml中的配置,在映射列表中新增Cooment类,并将版本号加1,如下所示:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <litepal>  
  3.     <dbname value="demo" ></dbname>  
  4.   
  5.     <version value="2" ></version>  
  6.   
  7.     <list>  
  8.         <mapping class="com.example.databasetest.model.News"></mapping>  
  9.         <mapping class="com.example.databasetest.model.Comment"></mapping>  
  10.     </list>  
  11. </litepal>  
没错,就是这么简单,仅仅两步,升级的操作就已经完成了,现在我们只需要操作一下数据库,comment表就会自动生成了,如下所示:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SQLiteDatabase db = Connector.getDatabase();  
那么我们还是通过.table命令来查看一下结果,如下图所示:


OK,comment表已经出来了,那么再通过pragma命令来查看一下它的表结构吧:


没有问题,comment表中目前有id和content这两列,和Comment模型类中的字段是保持一致的。

那么现在又来了新的需求,需要在comment表中添加一个publishdate列,该怎么办呢?不用怀疑,跟着你的直觉走,相信你已经猜到应该在Comment类中添加这样一个字段了吧,如下所示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class Comment {  
  2.       
  3.     private int id;  
  4.       
  5.     private String content;  
  6.       
  7.     private Date publishDate;  
  8.       
  9.     // 自动生成get、set方法   
  10.     ...  
  11. }  
然后呢?剩下的操作已经非常简单了,只需要在litepal.xml中对版本号加1就行了,如下所示:
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <litepal>  
  2.     <dbname value="demo" ></dbname>  
  3.   
  4.     <version value="3" ></version>  
  5.     ...  
  6. </litepal>  
这样当我们下一次操作数据库的时候,publishdate列就应该会自动添加到comment表中。调用Connector.getDatabase()方法,然后重新查询comment表结构,如下所示:


可以看到,publishdate这一列确实已经成功添加到comment表中了。

通过这两种升级方式的对比,相信你已经充分体会到了使用LitePal进行升级表操作所带来的便利了吧。我们不需要去编写任何与升级相关的逻辑,也不需要关心程序是从哪个版本升级过来的,唯一要做的就是确定好最新的Model结构是什么样的,然后将litepal.xml中的版本号加1,所有的升级逻辑就都会自动完成了。LitePal确实将数据库表的升级操作变得极度简单,使很多程序员可以从维护数据库表升级的困扰中解脱出来。

然而,LitePal却明显做到了更好。前面我们提到过关于删除列的问题,最终的结论是无法解决,因为SQLite是不支持删除列的命令的。但是如果使用LitePal,这一问题就可以简单地解决掉,比如说publishdate这一列我们又不想要了,那么只需要在Comment类中把它删除掉,然后将版本号加1,下次操作数据库的时候这个列就会不见了。

那么有的朋友可能会问了,不是说SQLite不支持删除列的命令吗?那LitePal又是怎样做到的呢?其实LitePal并没有删除任何一列,它只是先将comment表重命名成一个临时表,然后根据最新的Comment类的结构生成一个新的comment表,再把临时表中除了publishdate之外的数据复制到新的表中,最后把临时表删掉。因此,看上去的效果好像是做到了删除列的功能。

这也是使用框架的好处,如果没有框架的帮助,我们显然不会为了删除一个列而大废周章地去写这么多的代码,而使用框架的话,具体的实现逻辑我们已经不用再关心,只需要控制好模型类的数据结构就可以了。

另外,如果你想删除某一张表的话,操作也很简单,在litepal.xml中的映射列表中将相应的类删除,表自然也就不存在了。其它的一些升级操作也都是类似的,相信你已经能举一反三,这里就不再赘述了。

好了,今天对LitePal的介绍就到这里吧,下篇文章当中我们会学习使用LitePal来进行表关联的操作。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
24天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
6天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
33 19
|
10天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
24天前
|
存储 缓存 NoSQL
2款使用.NET开发的数据库系统
2款使用.NET开发的数据库系统
|
26天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
26天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
6天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
13 0
|
27天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
34 1
|
29天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
39 4