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 英文文檔

相關文章
相關標籤/搜索