推荐一个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方法,有可能一个月,有可能一年。查找成本也很高。