SQLite是Android内置的一个很小的关系型数据库。SQLiteOpenHelper是一个用来辅助管理数据库创建和版本升级问题的抽象类。我们可以继承这个抽象类,实现它的一些方法来对数据库进行自定义操作。下面两个方法必须重写:

  • public void onCreate(SQLiteDatabase db)
  • public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

另外SQLiteOpenHelper子类在构造实例时必须指定当前数据库的名称(name)、版本号(version)。而这里名称就决定了数据库存储时的文件名称,而这里的版本号与App在AndroidMainfest.xml定义的versionCode没有绝对关联。也就是在App更新时如果数据库的数据结构没有发生变化那么数据库的版本号则不用增加。

onCreate:调用时机是用户首次安装应用后启动,或是清除App数据库文件后启动。这时可以在这个函数中完成初始的数据表的创建。

onUpgrade:调用时机是用户在做应用更新,覆盖安装后启动,如果新版本中数据库版本号要比旧版本中的数据库版本号高则会调用。这时可以在这个函数完成数据库版本升级带来的旧版本的兼容问题,以及数据迁移问题。

还有一个一般情况下不需要重写,但在应用出现逆向降级(如应用由版本号4降级安装版本号为3的包)时必须重写的方法onDowngrade,如果应用降级覆盖安装时没有重写该方法则会崩溃。

在数据库版本升级时, 我们可能会遇到这样一些情况:

  • 需要扩展一个表的字段
  • 删除掉原来表上某个冗余的字段
  • 新建一个表

而处理上面这些问题都要在不损害旧数据库历史数据的前提下完成。这里我们假设用户手机上之前安装的是数据库版本为1的包,升级安装的是数据库版本号为2的包。这时我们要在数据库版本为2的包在去处理这些升级逻辑。

首先是扩展一个表的字段在onUpgrade中的实现为:

  1. @Override
  2. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  3. //旧数据库版本为1,才为表pedant添加一个student_name字段
  4. if(oldVersion < 2) {
  5. db.execSQL("ALTER TABLE pedant ADD COLUMN student_name text");
  6. }
  7. }

SQLite对ALTER TABLE的支持是有限的,你可以在一个存在表上添加一个字段到末尾,或者是改变表的名称。但如果你想做更复杂的操作,比如删除一个表已有的字段,就要重新创建这个表并完成数据迁移,而不能使用DROP COLUMN这样方便的命令了。详见SQLite
Frequently Questions

比如表pedant原来有三个字段a、b、c,现在想删除c字段,那么在onUpgrade中写法如下:

  1. @Override
  2. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  3. //旧数据库版本为1,删除表pedant的c字段
  4. if(oldVersion < 2) {
  5. db.beginTransaction();
  6. try {
  7. db.execSQL("CREATE TEMPORARY TABLE pe_backup (a, b);");
  8. db.execSQL("INSERT INTO pe_backup SELECT a, b FROM pedant;");
  9. db.execSQL("DROP TABLE pedant;");
  10. db.execSQL("CREATE TABLE pedant(a text, b text);");
  11. db.execSQL("INSERT INTO pedant SELECT a, b FROM pe_backup;");
  12. db.execSQL("DROP TABLE pe_backup;");
  13. db.setTransactionSuccessful();
  14. } finally {
  15. db.endTransaction();
  16. }
  17. }
  18. }

这样就既完成了对c字段的删除也保留了原来表上的数据。

最后一种情况最简单直接执行CREATE语句就要可以了。

  1. @Override
  2. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  3. //旧数据库版本为1,创建新表newtb
  4. if(oldVersion < 2) {
  5. db.execSQL("CREATE TABLE newtb(a text, b text);");
  6. }
  7. }

数据库在做升级时我们能明确地知道当前我们要对各旧表进行什么样的操作来兼容新版本。但如果在数据库降级时,情况就不一样了,针对我们开发新版本2时,
我们不能明确地知道以后的新版本比如版本3、4的数据库结构走向是怎样的。比如以后用户从版本3回退到我们正在开发的版本2,由于我们开发当时不能预知版本3的表结构,不知版本3的数据表能否兼容到版本2(假如版本3升级时删除了一个版本2一直在用的表字段,这时回退数据结构可能就不兼容了),那么我们在开发版本2时最稳妥的做法是重写onDowngrade时把所有当前版本将用到的表全部重建,即降级时扔掉以前全部的数据。

// 因为我们无法预知未来版本的表结构,向下兼容时最稳妥的方法就是将该版本自己需要的表重构一次
@Override
public void onDowngrade (SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS t1;");
db.execSQL("DROP TABLE IF EXISTS t2;");
db.execSQL("DROP TABLE IF EXISTS t3;");
db.execSQL("DROP TABLE IF EXISTS t4;");
....
onCreate(db); // 建表
}

最新文章

  1. Node.js:理解stream
  2. (1)编写一个接口ShapePara,要求: 接口中的方法: int getArea():获得图形的面积。int getCircumference():获得图形的周长 (2)编写一个圆类Circle,要求:圆类Circle实现接口ShapePara。 该类包含有成员变量: radius:public 修饰的double类型radius,表示圆的半径。 x:private修饰的double型变量x,
  3. servletFileUpload
  4. php4.3.4.4、apache2.0.4.8、mysql 4.0.26、window7 配置过程
  5. odoo中pos模块由于删除partner导致发生(你试图访问的单据已经删除)错误的解决方法
  6. linux的一点小随笔
  7. 解析Android消息处理机制:Handler/Thread/Looper &amp; MessageQueue
  8. (转)C#中的 break 与continue 的使用和注意
  9. POJ 2411
  10. Floodlight 启动过程分析
  11. HDU 1264 Counting Squares(模拟)
  12. 浅谈“Mysql”的基础操作语句
  13. linux下socket编程实例
  14. 记录一次安装OpenGL的漫长过程
  15. OpenResty:通过 Lua 扩展 NGINX 实现的可伸缩的 Web 平台
  16. java基础——IO流之File类
  17. 用递归方法求n阶勒让德多项式的值
  18. 去中心化存储项目终极指南 | Filecoin, Storj 和 PPIO 项目异同
  19. Ubuntu 14.10 下安装Ambari 问题汇总
  20. 转:C# 小数位数保留的方法集锦

热门文章

  1. 如何理解Spring IOC
  2. AspNetCoreApi 跨域处理
  3. C语言程序设计第五次作业——循环结构
  4. C语言第二次作业 ,
  5. mouseover,mouseout和mouseenter,mouseleave的区别及适用情况
  6. js ==与===区别
  7. EM vs REM vs PX,为什么你不应该”只用px“”
  8. 浅谈JS变量声明和函数声明提升
  9. jQuery 效果 – 动画
  10. python转lua最容易掉进去的坑--作用域