Android SQLite数据库,为什么删除表并在升级时重新创建

时间:2013-11-05 15:49:10

标签: android database sqlite database-update drop-table

在我关注的教程中,我看到很多其他地方, onUpgrade - > drop table如果存在,则重新创建表。

这是为了什么目的?

private static class DbHelper extends SQLiteOpenHelper{

    public DbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
                KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                KEY_NAME + " TEXT NOT NULL, " +
                KEY_HOTNESS + " TEXT NOT NULL);"
        );  
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
        onCreate(db);
    }       
}

5 个答案:

答案 0 :(得分:32)

嗯,Android应用程序中最常见的方法是在数据库升级有序时“重新”用户。并且考虑到任何本地数据库应该只镜像服务器端应用程序上的内容,只需删除数据库,重新创建数据库并从服务器重新填充,就比仔细规划从一个版本到另一个版本的迁移要容易得多。

肯定不是最佳方法,但它更容易。

举例说明它将如何实现迁移(从较旧版本的数据库更改为较新版本)

让我们在您的DbHelper类中定义您的数据库是版本1,在更高版本的应用程序(版本2)中,您需要在其中一个表中添加更多列。

所以你需要升级你的表并通过ALTER TABLE {tableName} ADD COLUMN COLNew {type}添加列;

检查此链接 - > Insert new column into table in sqlite ?

因此,您的onUpgrade()方法必须通过添加以下内容来反映该更改:

 @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch(oldVersion){
        case 1:
            db.execSQL("ALTER TABLE " + DATABASE_TABLE + " ADD COLUMN " + NEW_COLUMN_NAME + TYPE);
    }
}  

答案 1 :(得分:32)

我同意升级时应该添加列或向数据库添加表。大多数onupgrade样本实际上很糟糕,因为为什么我删除所有这些数据然后重新创建表?我发现这个博客文章我称之为 Adams增量更新方法。它还处理用户可能未在每个版本中升级您的应用程序的情况。

Here is a good blog on sqlite onupgrade that doesn't do drop table.

答案 2 :(得分:3)

取决于您想要创建的方法类型以及数据的重要性,表格的复杂程度。 示例:如果您的应用程序已经升级了很多次并且表结构已经有足够的时间更改,那么最好删除表并重新创建它,而不是编写代码来更改每个版本的db的结构,在这种方法中你将必须确保您可以备份服务器端的任何数据,以便保持正常。

从我的exp:如果你可以判断未来可能会有进一步的变化,那么重建会更好,否则会变得非常复杂

答案 3 :(得分:2)

这是一个干净的开始。方法onCreate具有当前有效的数据库结构。安装该应用程序的用户将执行此方法。对于正在升级的用户,将执行onUpgrade方法,并且DROP TABLE IF EXIST是一个干净的开始 - 以防旧表和新表的结构不同 - 删除它然后在onCreate方法中重新创建它。 希望这可以帮助! :)

答案 4 :(得分:0)

如果要维护表数据,可以将其转储到CSV文件中,然后在创建表后将其重新插入。 (无需将数据转储到服务器中) 这是转储数据的示例代码。您可以将文件名设置为表名。游标是从getAll语句

创建的
public boolean createCsvSaveToFile(Cursor cursor, String fileName) throws IOException {
    String csv = "";
    int colunmCount = cursor.getColumnCount();
    /* check if extarnal drive is readerble */
    if (!isExternalStorageWritable()) {
        fileError = "can not save to external storage";
        fileinfo = "Please mount your SD card";
        return false;
    } else {
        /* create the CSV */
        for (int i = 0; i < colunmCount; i++) {
            csv += QUOTES + cursor.getColumnName(i).toString() + QUOTES + INNER_DELIMITER;
        }
        csv = csv.replaceAll(",$", "");
        csv += LINE_END;
        if (cursor.moveToFirst()) {
            do {
                for (int i = 0; i < colunmCount; i++) {//GET COLUNM values
                    csv += QUOTES + cursor.getString(i) + QUOTES + INNER_DELIMITER;
                }
                csv = csv.replaceAll(",$", "");
                csv += LINE_END;
            } while (cursor.moveToNext());
        }
        /* save file */
        File file = getDataDir(fileName);
        FileOutputStream out = new FileOutputStream(file);
        out.write(csv.getBytes());
        out.flush();
        out.close();
        return true;
    }
}

这是一个用于插入数据的示例代码。假设CSV文件名与表名

相同
private void readFromFile(SQLiteDatabase database, File file) {
    boolean hasColunms = false;
    String tableName = file.getName().replaceAll(".csv$", "");
    String sql;
    String colunmNames = "";
    String colunmValues;
    try {
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;
        while ((line = br.readLine()) != null) {
            if (!hasColunms ) {
                /* get column names */
                line = line.replaceAll("\"", "");
                colunmNames = line;
                hasColunms = true;
            } else {
                line = line.replaceAll("\"", "'");
                colunmValues = line;
                sql = "INSERT INTO " + tableName + " (" + colunmNames + ") VALUES (" + colunmValues + ")";
                database.execSQL(sql);
            }
        }
        br.close();
    } catch (IOException e) {
        database.close();
        /* You may need to add proper error handling here
    }

循环遍历许多csv文件,可以使用以下代码

public boolean csvTodatabase(SQLiteDatabase database) {
    FileStuff f = new FileStuff();
    File time;
    /* check if extarnal drive is readerble */
    if (!f.isExternalStorageReadable()) {
        f.fileError = "can not read external storage";
        f.fileinfo = "Please remount your SD card";
        return false;
    } else {
        /* get all files from extarnal drive data */
        ArrayList<File> files = new ArrayList<File>();
        File directory = new File(FileStuff.DATA_DIRECTORY);
        if (!directory.exists()) {
            return false;
        }
        File[] fList = directory.listFiles();
        for (File file : fList) {
            if (file.isFile()) {
                files.add(file);
            }
        }  
        for (File csvfile : files) {
            readFromFile(database, csvfile);
        }
        return true;
    }
}

注意: readFromFile(database,csvfile);是上一个功能