一、升级SQlite字段类型

推荐一个SQLite工具SQliteBrowser
在Android项目开发过程中,总会使用数据库,Android上主要使用的是SQlite。
但是SQlite是一个轻量级的数据库,提供的功能是有限的。
新的需求是修改字段的类型

如果是普通的sql可以使用

alter table 表名alter column 字段名 字段类型

但是在SQlite中alter命令只支持修改表名和增加新列这里

那么方案应该是:
1、将原来的表重命名:name_temp
2、新建一个表name,该表中已经修改过字段名
3、将name_temp中的数据拷贝到name中
4、将temp表删除

聚个栗子:
正常的创建并插入数据:
1、创建表:

CREATE TABLE `student` (    `name`  TEXT,    `age`   TEXT);

2.插入数据

insert into student values("shang",25)

当前表的内容

现在发现age的类型是text,想要Integer类型。
1、rename

alter table student rename to student_temp;

2、创建新的表student,age字段类型是INTEGER

CREATE TABLE student (`name`  TEXT,`age`   INTEGER);

3、将temp中的数据拷贝到student表中

insert into student select name, age from student_temp;

4、把temp表删除掉

drop table student_temp

完成。

二、数据库升级中的坑

但是在数据库升级时候会有坑
数据库版本是2的代码:
相对于版本1做的升级是讲age字段的类型从TEXT改为INTEGER。

//创建新表private void createTables(SQLiteDatabase db) {        try {        String createStr = "CREATE TABLE `student` (    `name`  TEXT,`age`  INTEGER);";        db.execSQL(createStr);        } catch (Exception ex) {        }    }    //数据库升级    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        try {            switch (oldVersion) {            case 1:                student1to2(db);                // 刻意进行穿透。 按序升级            default:                break;            }        } catch (Exception ex) {            createTables(db);        }    }    public void student1to2(db){        //1、重命名        String renameStr = "alter table student rename to student_temp;";        db.execSQL(renameStr);        //2、创建新的表        createTables(db);        //3、拷贝        String copyStr = "insert into student select name, age from student_temp;";        db.execSQL(copyStr);        //4、删除表        String dropStr = "drop table student_temp";        db.execSQL(dropStr);    }

数据库版本是3的代码:
相对于2变化的是增加一列school

//创建新表private void createTables(SQLiteDatabase db) {        try {        String createStr = "CREATE TABLE `student` (    `name`  TEXT,`age`  INTEGER,`school`     TEXT);";        db.execSQL(createStr);        } catch (Exception ex) {        }    }    //数据库升级    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        try {            switch (oldVersion) {            case 1:                student1to2(db);                // 刻意进行穿透。 按序升级            case 2:                student2to3(db);                // 刻意进行穿透。 按序升级            default:                break;            }        } catch (Exception ex) {            createTables(db);        }    }    public void student1to2(SQLiteDatabase db){        //1、重命名        String renameStr = "alter table student rename to student_temp;";        db.execSQL(renameStr);        //2、创建新的表        createTables(db);        //3、拷贝        String copyStr = "insert into student select name, age from student_temp;";        db.execSQL(copyStr);        //4、删除表        String dropStr = "drop table student_temp";        db.execSQL(dropStr);    }    public void student2to3(SQLiteDatabase db) {        String sql = "ALTER TABLE student ADD COLUMN school TEXT;"        db.execSQL(sql);    }

如果用户的安装app的版本依次是1,2,3,则没有错。

如果用户的APP版本是1直接跳到3,则会出错。
出问题的原因是app启动会检测当前正在使用的数据库版本(1),即将升级的版本(3),数据库需要升级,可以看到onUpgrade方法中不支持1直接升级到3,而是1-2-3升级,在student1to2中使用了createTables,而在3中createTables已经对student的表增加一列(school),则会错误如下:

table student has 3 columns but 2 values were supplied: insert into student select name, age from student_temp;

有人会问,如果2升级到3是减少一列(age),是否会出问题那?答案是依然会出问题,错误:

table student has 1 columns but 2 values were supplied: insert into student select name, age from student_temp;

可能有人会说可以使用以下代码进行复制:

insert into student(name, age) select name, age from student_temp;

新表是增加一列(school)的话,没有问题;
如果新表去掉一列,继续使用上述的语句,则会出现下面错误:

table student has no column named age: insert into student(name, age) select name, age from student_temp

正确的处理方法是有一个createTables方法,还有一个createTables1to2的方法,在数据库版本是2的时候,这两个方法是完全一样的,在数据库版本升级到3时候,只需要修改createTables方法,而不修改createTables1to2的内容,createTables1to2是从1升级到2专用的方法。

正确的版本3的代码应该是:

//创建新表private void createTables(SQLiteDatabase db) {        try {        String createStr = "CREATE TABLE `student` (    `name`  TEXT,`age`  INTEGER,`school`     TEXT);";        db.execSQL(createStr);        } catch (Exception ex) {        }    }//数据库升级    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        try {            switch (oldVersion) {            case 1:                student1to2(db);                // 刻意进行穿透。 按序升级            case 2:                student2to3(db);            default:                break;            }        } catch (Exception ex) {            createTables(db);        }    }    public void student1to2(SQLiteDatabase db){        //1、重命名        String renameStr = "alter table student rename to student_temp;";        db.execSQL(renameStr);        //2、创建新的表        createTables(db);        //3、拷贝        String copyStr = "insert into student select name, age from student_temp;";        db.execSQL(copyStr);        //4、删除表        String dropStr = "drop table student_temp";        db.execSQL(dropStr);    }    public void student2to3(SQLiteDatabase db) {        String sql = "ALTER TABLE student ADD COLUMN school TEXT;"     db.execSQL(sql);    //1到2升级专用    public void createTables1to2(SQLiteDatabase db){    try {        String createStr = "CREATE TABLE `student` (    `name`  TEXT,`age`  INTEGER);";        db.execSQL(createStr);        } catch (Exception ex) {        }}

这个bug出现的出现取决于什么时候修改createTables方法,有可能一个月,有可能一年。查找成本也很高。

更多相关文章

  1. OpenCV4Android开发之旅(一)----OpenCV2.4简介及 app通过Java接
  2. 在android中使用OrmLite数据库框架
  3. Android平台调用WebService详解
  4. Android-sharedUserId
  5. Android下创建一个sqlite数据库
  6. Android下Content Provider使用
  7. 如何将android SDK sample中的例子添加到eclipse中
  8. Android开发学习系列-----开发环境准备
  9. Android个版本适配之7.0

随机推荐

  1. Android系统介绍
  2. Android中Intent传递对象的两种方法(Seri
  3. 【Android】小白进阶之接口和抽象类的使
  4. 获取Android开机启动项列表
  5. Retrofit使用总结
  6. Android中文API(99)—— RelativeLayout
  7. Android中IntentService的使用及其源码解
  8. Android采用Junit进行应用单元测试
  9. Android Debug keystore系统位置
  10. Android中的四种动画效果