相信不少人在做项目时会数据库升级,可能涉及到数据结构的变化,下面写了个工具类,可以帮助在数据结构变化时,保留原数据不丢。
/**
* Created by zeng on 2017/1/13.
* 为了适用于如greenDao这样的框架,使用反射调用相应的方法
*/
public class DbUtils {
public static class Column {
public static final String INTEGER = "INTEGER";
public static final String TEXT = "TEXT";
public static final String REAL = "REAL";
public static final String DATE = "DATE";
public String name;
public String type;
public Object defualtValue;
public Column() {
}
public Column(String name, String type, Object defualtValue) {
this.name = name;
this.type = type;
this.defualtValue = defualtValue;
}
}
private static void execSQL(Object db, String sql) {
try {
db.getClass().getMethod("execSQL", String.class).invoke(db, sql);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void execSQL(Object db, String sql, Object[] bindArgs) {
try {
db.getClass().getMethod("execSQL", String.class, Object[].class).invoke(db, sql, bindArgs);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void invokeVoidNoPrama(Object db, String methodName) {
try {
db.getClass().getMethod(methodName).invoke(db);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void beginTransaction(Object db) {
invokeVoidNoPrama(db, "beginTransaction");
}
private static void endTransaction(Object db) {
invokeVoidNoPrama(db, "endTransaction");
}
private static void setTransactionSuccessful(Object db) {
invokeVoidNoPrama(db, "setTransactionSuccessful");
}
/**
* 重命名表
*/
public static void renameTable(Object db, String oldName, String newName) {
try {
execSQL(db, "ALTER TABLE " + oldName + " RENAME TO " + newName);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除表
*/
public static void deleteTable(Object db, String tableName) {
try {
execSQL(db, "DROP TABLE " + tableName);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据表的所有字段名
*/
public static Column[] getColumns(Object db, String tableName) {
Column[] columns = null;
Cursor cursor = null;
try {
String sql = "PRAGMA table_info(" + tableName + ")";
Method method = db.getClass().getMethod("rawQuery", String.class, String[].class);
cursor = (Cursor) method.invoke(db, sql, null);
int nameIndex = cursor.getColumnIndex("name");
if (nameIndex == -1) {
return null;
}
int index = 0;
columns = new Column[cursor.getCount()];
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
columns[index] = new Column();
columns[index].name = cursor.getString(nameIndex);
columns[index].type = cursor.getString(cursor.getColumnIndex("type"));
int defaultValueIndex = cursor.getColumnIndex("dflt_value");
switch(cursor.getType(defaultValueIndex)) {
case Cursor.FIELD_TYPE_BLOB:
columns[index].defualtValue = cursor.getBlob(defaultValueIndex);
break;
case Cursor.FIELD_TYPE_FLOAT:
columns[index].defualtValue = cursor.getDouble(defaultValueIndex);
break;
case Cursor.FIELD_TYPE_INTEGER:
columns[index].defualtValue = cursor.getLong(defaultValueIndex);
break;
case Cursor.FIELD_TYPE_STRING:
columns[index].defualtValue = cursor.getString(defaultValueIndex);
break;
}
index++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return columns;
}
/**
* 删除列
* @param columnNames 要删除的列名
*/
public static void deleteColumns(Object db, String tableName, String... columnNames) {
try {
beginTransaction(db);
Column[] columns = getColumns(db, tableName);
if (columns != null) {
//重命名原表
String tmpTableName = "t" + UUID.randomUUID().toString().replaceAll("-", "_");
execSQL(db, "ALTER TABLE " + tableName + " RENAME TO " + tmpTableName);
//新建表sql语句
String newTableSql = "CREATE TABLE " + tableName + "(";
List list = Arrays.asList(columnNames);
//复制数据sql语句
String copySql = "INSERT INTO " + tableName + " SELECT ";
for (Column column : columns) {
if (!list.contains(column.name)) {
newTableSql += column.name + " " + column.type + ",";
copySql += column.name + ",";
}
}
newTableSql = newTableSql.substring(0, newTableSql.length() - 1) + ")";
execSQL(db, newTableSql);
//复制数据到新表
copySql = copySql.substring(0, copySql.length() - 1) + " FROM " + tmpTableName;
execSQL(db, copySql);
//删除临时表
execSQL(db, "DROP TABLE " + tmpTableName);
}
setTransactionSuccessful(db);
} catch (Exception e) {
e.printStackTrace();
} finally {
endTransaction(db);
}
}
/**
* 添加列
* @param columns 需要添加的列的信息
*/
public static void addColumns(Object db, String tableName, Column... columns) {
try {
beginTransaction(db);
for (Column column : columns) {
String sql = "ALTER TABLE " + tableName + " ADD " + column.name + " " + column.type;
Object[] bindArgs = null;
if (column.defualtValue != null) {
if (column.defualtValue instanceof String) {
sql += " DEFAULT '" + column.defualtValue + "'";
} else if (column.defualtValue instanceof byte[]) {
//如果是字节数组,先插入列,再设置默认数据
execSQL(db, sql);
sql = "UPDATE " + tableName + " SET " + column.name + "=?";
bindArgs = new Object[]{column.defualtValue};
} else {
sql += " DEFAULT " + column.defualtValue;
}
}
if (bindArgs == null) {
execSQL(db, sql);
} else {
execSQL(db, sql, bindArgs);
}
}
setTransactionSuccessful(db);
} catch (Exception e) {
e.printStackTrace();
} finally {
endTransaction(db);
}
}
/**
* 更新列名
* @param map key为旧列名,value为新列名
*/
public static void updateColumnNames(Object db, String tableName, Map map) {
try {
beginTransaction(db);
Column[] columns = getColumns(db, tableName);
if (columns != null) {
//重命名原表
String tmpTableName = "t" + UUID.randomUUID().toString().replaceAll("-", "_");
execSQL(db, "ALTER TABLE " + tableName + " RENAME TO " + tmpTableName);
//新建表sql语句
String newTableSql = "CREATE TABLE " + tableName + "(";
//复制数据sql语句
String copySql = "INSERT INTO " + tableName + " SELECT ";
Set keySet = map.keySet();
for (Column column : columns) {
if (keySet.contains(column.name)) {
newTableSql += map.get(column.name) + " " + column.type + ",";
} else {
newTableSql += column.name + " " + column.type + ",";
}
copySql += column.name + ",";
}
newTableSql = newTableSql.substring(0, newTableSql.length() - 1) + ")";
execSQL(db, newTableSql);
//复制数据到新表
copySql = copySql.substring(0, copySql.length() - 1) + " FROM " + tmpTableName;
execSQL(db, copySql);
//删除临时表
execSQL(db, "DROP TABLE " + tmpTableName);
}
setTransactionSuccessful(db);
} catch (Exception e) {
e.printStackTrace();
} finally {
endTransaction(db);
}
}
}