31

在我正在关注的教程以及我看到的更多地方,onUpgrade -> 如果存在则删除表,然后重新创建表。

这样做的目的是什么?

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);
    }       
}
4

5 回答 5

32

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

这当然不是最好的方法,但它更容易。

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

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

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

检查此链接 ->在 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);
    }
}  
于 2013-11-05T15:53:08.023 回答
32

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

这是关于 sqlite onupgrade 的一个很好的博客,它不做删除表。

于 2013-11-07T13:17:02.317 回答
3

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

从我的经验来看:如果你能判断未来可能会有进一步的变化,那么重新创建会更好,否则它会变得相当复杂

于 2013-11-05T16:09:33.460 回答
2

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

于 2013-11-05T15:59:56.817 回答
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); 是前一个函数

于 2014-10-27T06:07:55.920 回答