【问题标题】:SQLite “after update” trigger in Android does not appear to run after every record updateAndroid 中的 SQLite“更新后”触发器似乎不会在每次记录更新后运行
【发布时间】:2021-06-11 16:08:05
【问题描述】:

问题: 如果有的话,什么会导致 SQLite 触发器仅在某些时候运行?

总结:我用 SQLite 编写的新触发器得到了看似不一致的结果,我想了解是否发生这种情况,因为我在 SQL 中犯了一个错误/Java 代码,或者如果我可能遇到了 SQL 触发器可能无法按预期工作的罕见情况。

详情: 在处理 Android 项目时,我遇到了我最初认为是 SQLite 触发器的问题。但是,由于我的新触发器与同一项目中的其他几个工作触发器完全匹配(表名除外),我开始怀疑我的 Java 代码是否是问题所在。

我遇到问题的触发器的目的是监视对 TableA 的更改,例如在 DismissDateUTC 列中添加一个值。当对 TableA 中的任何数据进行更新时,触发器应该将更新后的 TableA 记录的 ID 放入 TableAChanges 中,后者稍后用于确定哪些记录已更新并应发送回 Web 服务器。

当使用数据库检查器(在 Android Studio v4.2.1 中)或程序“DB Browser for SQLite”并在 TableA 上手动运行更新查询时,触发器完全按预期工作,并且记录显示在 TableAChanges 中。当我以编程方式对 TableA 进行更新时,触发器似乎没有运行。我相信它没有运行,因为在将更新写入 TableA 后没有记录写入 TableAChanges。

到目前为止我尝试过的事情:

  • 在 Android 7.1.1 设备上运行应用程序(触发器不起作用)
  • 在 Android 8.1.0 设备上运行应用程序(触发器不起作用)
  • 在 Android 11 设备上运行应用(触发器不起作用)
  • 从 Android Studio DB Inspector 对 TableA 运行手动更新查询(触发器正在工作)
  • 从 DB Browser for SQLite 对 TableA 运行手动更新查询(触发器正在工作)
  • 通过“amitshekhar”从 Android 调试数据库对 TableA 运行手动更新查询(触发器正在工作)

表和触发器 SQL:

CREATE TABLE TableA (
    ID INTEGER PRIMARY KEY NOT NULL 
    -- (more table columns) --
    , DismissDateUTC TEXT NULL
);

CREATE TABLE TableAChanges (
    ID INTEGER PRIMARY KEY NOT NULL
);

CREATE TRIGGER trigTableA_U AFTER UPDATE ON TableA
BEGIN
    REPLACE INTO TableAChanges(ID)
        SELECT old.ID;  
END

TableA DAO 类中的 Android Java:

public boolean saveChanges() {
    boolean ret = true;
    
    ContentValues cv = new ContentValues();
    cv.put("ID", mId);
    // (more table columns)
    cv.put("DismissDateUtc", mDismissDateUtc);

    SQLiteDatabase db = DB.getInstance().getWritableDatabase();
    try {
        db.replaceOrThrow("TableA", null, cv);
    } catch (SQLException e) {
        ExceptionDao.logToAcra(e);
        ret = false;
    } finally {
        db.close();
    }
    
    return ret;
}

*** 为了透明起见,我已经知道我可以通过手动将记录写入 TableAChanges 来解决这个问题。但是,我仍然想在这里发布这个问题,因为我希望了解这个问题的原因,而不是忽略这个问题。

【问题讨论】:

    标签: java android sqlite triggers android-sqlite


    【解决方案1】:

    触发器不起作用的原因是因为它是一个AFTER UPDATE触发器,这意味着它只有在表更新后才会起作用。

    另一方面,replaceOrThrow() 不更新表。
    它实际上正在执行一个INSERT OR REPLACE INTO... 或简单的REPLACE INTO... 语句,如果新的ID 在表中不存在,则在表中插入一个新行,或者如果它存在,则删除包含现有@ 的行987654327@ 并插入新行。

    【讨论】:

    • 在处理现有记录时,我没有意识到 db.replaceOrThrow() 会删除,然后插入而不是更新现有行。有了这种新的理解,我能够通过调用 db.update() 来解决我的问题,以确保更改的行被更新而不是被替换。
    • @BenBloodworth 还有您可能希望尝试的 UPSERT:sqlite.org/lang_UPSERT.html,但对于此语句,您必须使用 execSql()
    猜你喜欢
    • 1970-01-01
    • 2017-07-22
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多