常常咱們會碰到這種需求:html
須要記錄一下用戶的瀏覽過哪些商品;或者搜索歷史,每次搜索時須要更新搜索歷史;...
一般這些需求咱們須要先建立一個相關歷史的表his_table,在每次insert以前須要檢索下這條數據是否已存在。
繁瑣的點在於每次insert都須要query,才能夠肯定接下來的inser or update操做。
甚至更復雜的業務,修改A表的後又須要修改B表的數據,這樣的話就須要操做兩個表,使咱們的代碼更加臃腫。
而數據庫觸發器就能夠解決這類問題,今天就來介紹一下SQLite3數據庫觸發器在Android的使用。
複製代碼
Show your code!!!git
比方說咱們的數據建表語句是這樣的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的意思就是建立了一個觸發器,在每次插入數據以前刪除和此次插入數據相同的舊數據。下面會分別解釋各個字段什麼意思。數據庫
咱們能夠拆解一下這條建立觸發器SQLbash
CREATE TRIGGER // 建立觸發器
auto_remove // 觸發器名稱,後期能夠用來查詢和移除觸發器
BEFORE // 在事件以前觸發,改成AFTER就是以後觸發
INSERT // 在插入事件觸發,還支持DELETE、UPDATE
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來完成更高級的功能。可是它也有一些限制:
好比,產品經理又加了 一個插入數據時自動刪除失效數據 的需求,不慌只須要修改一下觸發器。不過觸發器不支持修改,只能刪除後新建
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()
}
複製代碼
若是有什麼錯誤或者不足的地方,歡迎指正