使用 onUpgrade 不起作用,我错过了啥吗?谢谢

Posted

技术标签:

【中文标题】使用 onUpgrade 不起作用,我错过了啥吗?谢谢【英文标题】:Using onUpgrade doesn't work, am I missing something? Thank you使用 onUpgrade 不起作用,我错过了什么吗?谢谢 【发布时间】:2022-01-13 23:20:16 【问题描述】:

这是我的资产文件夹中的数据库名称,我看到有人说资产不可写。

public class DatabaseAssets_Milestones extends SQLiteOpenHelper 
    private static String dbName = "milestones.db";
    Context context;
    File dbFile;

这是我的构造函数。

    public DatabaseAssets_Milestones(@Nullable Context context) 
        super(context, dbName, null, 2);
        this.context = context;
        File DB_PATH = context.getDatabasePath(dbName);
        String db = DB_PATH.getAbsolutePath();
        dbFile = new File(db);

        if(!dbFile.exists())
            if (!dbFile.getParentFile().exists()) 
                dbFile.mkdirs();
            
            copyDataBase(dbFile.getPath());
        
    

这是我的复制数据库方法。

    private void copyDataBase(String dbPath)

        try

            InputStream assetDB = context.getAssets().open("databases/"+"milestones.db");
            OutputStream appDB = new FileOutputStream(dbPath,false);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = assetDB.read(buffer)) > 0) 
            appDB.write(buffer, 0, length);
            
            appDB.flush();
            appDB.close();
            assetDB.close();

        catch(IOException e)
            e.printStackTrace();
        
    

    @Override
    public void onCreate(SQLiteDatabase db) 
    

我在这里遗漏了什么吗?还是我的其他代码中的某些内容?

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

【问题讨论】:

【参考方案1】:

假设您有一个版本 1 的数据库并更改为版本 2,您所拥有的将:-

    在数据库存在时跳过资产副本。 调用onUpgrade,后者调用onCreate,从数据库中删除表,然后为您留下一个没有删除表的数据库。

onCreate 删除表的方法不会生成资产文件的副本。 从 onCreate 中调用 copyDatabase 方法可能会导致问题。

如果您想要复制更改后的资产文件,那么您可能会发现 this 或 this 很有用。

如果您真的想在 onUpgrade 方法中将资产文件复制为新数据库(这样),那么您可以这样做:-

    使用修改后的copyDataBase,你可以传递一个参数来修改copyDataBase的名字,从而导致

      传递给 onUpgrade 方法的 SQliteDatabase,以及 从具有不同文件名的资产复制的 SQliteDatabase。

    ATTACH 将资产复制数据库(2.) 到传递的数据库(1.)

    对传递的数据库进行准备性更改,例如删除表以及可能的索引和触发器。

    将初始更改应用于传递的数据库,例如重新创建已删除的表。

    根据需要填充更改的表(可能通过合适的插入/更新查询从资产副本数据库中提取数据并在传递的数据库中插入/更新新的/更改的表)。

    应用最终更改,例如创建索引和触发器到传递的数据库 7. 将索引留到最后会更有效率。 7. 你可能不希望触发器触发,因此它们可能应该留到最后。

    DETACH 资产副本数据库

    使用 File 的 delete 方法删除资产副本数据库。

以上仅为粗略指导,根据要求,可能会有偏差。 同样,取决于要求,例如如果您想基本上删除所有项目定义的表,然后从资产副本中添加所有表,那么您可以通过询问适当的 sqlite_master 来自动执行此操作(传递给删除现有表,以及资产副本的 sqlite_master 来创建和填充替换表)。 虽然对于 Room 的内容类似于 answer 中的 PrepackagedDatabaseCallback 方法中所做的事情 (除了 CREATE .... 语句已被硬编码,它们必须是它们可能的样子从资产副本的 sqlite_master 中提取)

【讨论】:

以上是关于使用 onUpgrade 不起作用,我错过了啥吗?谢谢的主要内容,如果未能解决你的问题,请参考以下文章

Nginx 位置指令似乎不起作用。我错过了啥吗?

为啥 BlockInput 对我不起作用?我忘了啥吗?

我写了一个不工作的触发器。我错过了啥吗?

执行 Task.Cancel 方法时引发异常。我错过了啥吗? [复制]

jQuery 类选择器和单击事件,我错过了啥吗?

git bisect 并找到最后一个好的提交 - 我错过了啥吗?