SQLite Trigger 简化你的数据库操做

Ctrl +Z

前言

生活不仅有眼前的苟且,还有Ctrl + C 和 V

常常咱们会碰到这种需求:html

须要记录一下用户的浏览过哪些商品;或者搜索历史,每次搜索时须要更新搜索历史;...
一般这些需求咱们须要先建立一个相关历史的表his_table,在每次insert以前须要检索下这条数据是否已存在。
繁琐的点在于每次insert都须要query,才能够肯定接下来的inser or update操做。
甚至更复杂的业务,修改A表的后又须要修改B表的数据,这样的话就须要操做两个表,使咱们的代码更加臃肿。
    而数据库触发器就能够解决这类问题,今天就来介绍一下SQLite3数据库触发器在Android的使用。
复制代码

Show your code!!!git

SQLite 触发器

触发器(Trigger)是数据库的回调函数,它会在指定的数据库事件发生时自动执行

比方说咱们的数据建表语句是这样的github

CREATE TABLE db_list_table (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id TEXT NOT NULL,
    item_id INTEGER NOT NULL,
    date TimeStamp DEFAULT (datetime('now','localtime'))
 );
复制代码
// 插入时间戳yyyy-MM-dd HH:mm:ss,更多请查看文章末尾SQLite时间函数
// 时间函数是基本能够知足常见的格式
date TimeStamp DEFAULT (datetime('now','localtime'))
复制代码

你觉得这样就结束了?(ಡωಡ)(ಡωಡ)sql

CREATE TRIGGER auto_remove BEFORE INSERT
    ON db_list_table
    BEGIN
        DELETE FROM db_list_table WHERE NEW.user_id=user_id AND NEW.item_id=item_id;
    END;
复制代码

这句SQL的意思就是建立了一个触发器,在每次插入数据以前删除和此次插入数据相同的旧数据。下面会分别解释各个字段什么意思。数据库


SQLite 触发器(Trigger)是数据库的回调函数,它会在指定的数据库事件发生时自动执行

  • SQLite仅支持FOR EACH ROW触发器,不支持FOR EACH STATEMENT触发器,因此不用显式的声明FOR EACH ROW
  • 能够指定在特定的数据库表发生 DELETE、INSERT 或 UPDATE 时触发,或在一个或多个指定表的列发生更新时触发
  • BEFORE 或 AFTER 关键字决定什么时候执行触发器动做,决定是在关联行的插入、修改或删除以前或者以后执行触发器动做
  • 若是提供 WHEN 语句,则只针对 WHEN 语句为true的指定行执行 SQL 语句。若是没有提供 WHEN 语句,则针对全部行执行 SQL 语句
  • WHEN 语句和触发器动做均可以使用 NEW.column-name 和 OLD.column-name 来引用当前操做行的value,其中 column-name 是从与触发器关联的表的列名
  • 当触发器相关联的表删除时,自动删除触发器
  • 要修改的表必须存在于同一数据库中,做为触发器被附加的表或视图

建立触发器

咱们能够拆解一下这条建立触发器SQLbash

CREATE TRIGGER // 建立触发器
 auto_remove    // 触发器名称,后期能够用来查询和移除触发器
 BEFORE         // 在事件以前触发,改成AFTER就是以后触发
 INSERT         // 在插入事件触发,还支持DELETEUPDATE
 ON db_list_table   // 操做哪一个表
    BEGIN   // 触发语句开始
        // 触发语句,删除db_list_table表中和当前插入数据的user_id、item_id相同的数据
        DELETE FROM db_list_table WHERE user_id=NEW.user_id AND item_id=NEW.item_id;// 不要忘了分号
        // 由于触发事件是INSERT,因此表单数据要用NEW.column-name引用;
        // 可能比较绕,你品品,你细品,是否是颇有道理(ಡωಡ)
    END;    // 触发语句结束
复制代码

NEW 和OLD 关键字的英文文档函数

Both the WHEN clause and the trigger actions may access elements of the row being inserted, deleted or updated using references of the form "NEW.column-name" and "OLD.column-name", 
where column-name is the name of a column from the table that the trigger is associated with.
OLD and NEW references may only be used in triggers on events for which they are relevant, as follows:

    INSERT	NEW references are valid    // 插入时NEW有效
    UPDATE	NEW and OLD references are valid    // 均有效
    DELETE	OLD references are valid    // 删除时OLD有效
    // 这里的INSERT,UPADATE,DELETE指的是触发动做类型,不是触发语句类型。就是BEFOR/AFTER后面的操做
复制代码

建立完这个触发器以后每次插入新数据前就会自动检索已存在的数据,存在的话就会删除,而后再插入。 这样的话咱们就不须要维候插入和更新的逻辑,所有交由触发器自动管理。ui

固然咱们也可使用触发器更新其余表的数据,好比这里作了一下数据库数据的备份,记录主表全部的插入记录。spa

// 建立备份表
CREATE TABLE db_list_backup_table (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id TEXT NOT NULL,
    item_id INTEGER NOT NULL,
    date TimeStamp NOT NULL
);
// 建立备份触发器
CREATE TRIGGER back_up AFTER INSERT 
ON db_list_table 
    BEGIN 
        INSERT INTO db_list_backup_table (user_id,item_id,date) VALUES (NEW.user_id,NEW.item_id,NEW.date); 
        // 这里触发动做是INSERT,使用NEW关键字引用value
    END;

复制代码

插入一些数据看一下备份效果 code

备份触发器
能够看到数据在db_list_table中是没有重复的,可是db_list_backup_table是有主表的全部插入数据的

你们可能已经发现了,BEGIN 和END中间的触发语句就是一条SQL的删除语句,没错触发语句就是一条普通的删除语句,也能够插入一些默认值(好比更详细的时间戳),甚至使用更复杂的SQL来完成更高级的功能。可是它也有一些限制:

  • 要在UPDATE,DELETE或INSERT 语句中修改的表只支持同一个数据库下的表
  • 不支持UPDATE和DELETE 语句的ORDER BY和LIMIT子句
  • 不支持INSERT语句的'INSERT INTO table_name DEFAULT VALUES'形式

好比,产品经理加了 一个插入数据时自动删除失效数据 的需求,不慌只须要修改一下触发器。不过触发器不支持修改,只能删除后新建

删除触发器

drop trigger trigger_name // 根据触发器名称删除
复制代码
CREATE TRIGGER auto_remove BEFORE INSERT
    ON db_list_table
    BEGIN
        DELETE FROM db_list_table WHERE 
            strftime('%s','now') - strftime('%s',date) >= 30 // 30s之前的数据算失效
        OR 
            (NEW.user_id=user_id AND NEW.item_id=item_id);
    END;
复制代码
// 将当前时间转换为秒数
strftime('%s','now')
复制代码

查询触发器

// 经过sqlite_master 查询,不是查询咱们本身的代表
SELECT name FROM sqlite_master WHERE type = 'trigger';
复制代码

执行多条SQL时记得使用事务,保证语句的在预期内执行

db.beginTransaction()
try {
    db.execSQL("sql a")
    db.execSQL("sql b")
    // 数据库事务成功
    db.setTransactionSuccessful()
} catch (e: SQLException) {
    e.printStackTrace()
    // todo 异常处理
} finally {
    db.endTransaction()
}
复制代码

总结

  • 执行多条SQL时记得使用事务,保证语句的在预期内执行(废话
  • SQLite Trigger是数据库的回调函数,它会在数据库表发生 DELETE、INSERT 或 UPDATE 时的先后自动执行
  • 触发语句虽然很强大,可是也有相应的限制,并不能支持全部语法
  • 可使用 NEW.column-name 和 OLD.column-name 来引用当前操做行的value
  • 触发器能够增删查,可是不方便修改。若是表结构修改时,记得迁移触发器

应用截图

应用截图

项目源码已上传Github

若是有什么错误或者不足的地方,欢迎指正

Github
邮箱 dede.hu@qq.com

End

相关连接

SQLite 触发器文档
SQLite 时间函数文档

SQLite 时间函数中文文档

SQLite 英文文档

相关文章
相关标签/搜索