diff --git a/src/main/resources/database.db b/src/main/resources/database.db index 4779ce0..4f26679 100644 Binary files a/src/main/resources/database.db and b/src/main/resources/database.db differ diff --git a/src/main/resources/docs/only-one-default-true-in-sqlite3-datatable-trigger.md b/src/main/resources/docs/only-one-default-true-in-sqlite3-datatable-trigger.md new file mode 100644 index 0000000..e05b90e --- /dev/null +++ b/src/main/resources/docs/only-one-default-true-in-sqlite3-datatable-trigger.md @@ -0,0 +1,101 @@ +## 使用触发器在 SQLite3 数据表内实现唯一的默认配置 + +系统设计了 `RequestInfo` 和 `ProxySetting` 两个实体类来配置请求信息和代理设置,对应到 SQLite 表中分别是 `request_info` 和 `proxy_setting`,两者都有 `is_default` 字段。 + +由于同一时间内,数据表中只能存在一条 `is_default` 为 1 的记录,所以要进行一些设置。按照传统方法,需要在 Java 代码中,任何对数据记录 CRUD 的地方进行限制,但由于需要覆写的方法太多,又容易有纰漏,所以直接在数据表内用触发器限制。 + +以 `proxy_setting` 表为例,我们需要 5 个触发器来实现这个功能。 + +### AFTER INSERT is_default = 1 时的触发器 + +```sqlite +CREATE TRIGGER default_1_after_insert_proxy_setting + AFTER INSERT + ON proxy_setting + FOR EACH ROW + WHEN CAST (NEW.is_default AS INTEGER) = 1 +BEGIN + UPDATE proxy_setting + SET is_default = 0 + WHERE is_default = 1 AND + id <> NEW.id; +END; +``` + +在 INSERT 之后,对每一行,如果 is_default = 1 的,如果旧记录有 is_default = 1 的,将旧记录 is_default 置为 0. + +### AFTER UPDATE is_default = 1 时的触发器 + +```sqlite +CREATE TRIGGER default_1_after_update_proxy_setting + AFTER UPDATE + ON proxy_setting + FOR EACH ROW + WHEN CAST (NEW.is_default AS INTEGER) = 1 +BEGIN + UPDATE proxy_setting + SET is_default = 0 + WHERE id <> NEW.id AND + is_default = 1; +END; +``` + +和 INSERT 类似,但是 UPDATE 场景。 + +### BEFORE INSERT is_default = 0 时的触发器 + +```sqlite +CREATE TRIGGER default_0_before_insert_proxy_setting + BEFORE INSERT + ON proxy_setting + FOR EACH ROW + WHEN NEW.is_default = 0 AND + ( + SELECT COUNT( * ) + FROM proxy_setting + WHERE is_default = 1 + ) += 0 +BEGIN + SELECT RAISE(ABORT, "需要配置一条默认代理"); +END; +``` + +在插入之前,如果本条为 0 且数据表内不包含默认配置(即 is_default = 1的记录)的,不允许插入。 + +### BEFORE UPDATE is_default = 0 时的触发器 + +```sqlite +CREATE TRIGGER default_0_before_update_proxy_setting + BEFORE UPDATE + ON proxy_setting + FOR EACH ROW + WHEN NEW.is_default = 0 AND + ( + SELECT COUNT( * ) + FROM proxy_setting + WHERE is_default = 1 AND + id <> NEW.id + ) += 0 +BEGIN + SELECT RAISE(ABORT, "需要配置一条默认代理"); +END; +``` + +和 INSERT 场景类似。 + +### BEFORE DELETE 触发器 + +```sqlite +CREATE TRIGGER protect_default_proxy_setting + BEFORE DELETE + ON proxy_setting + FOR EACH ROW + WHEN OLD.is_default = 1 +BEGIN + SELECT RAISE(ABORT, "待删除数据中有默认代理,不允许删除!"); +END; +``` + +如果待删除的记录中包含默认配置,则不允许删除。 \ No newline at end of file diff --git a/src/main/resources/only-one-default-true-in-sqlite3-datatable-trigger.md b/src/main/resources/only-one-default-true-in-sqlite3-datatable-trigger.md deleted file mode 100644 index 87ff934..0000000 --- a/src/main/resources/only-one-default-true-in-sqlite3-datatable-trigger.md +++ /dev/null @@ -1,2 +0,0 @@ -## 使用触发器在 SQLite3 数据表内实现唯一的默认配置 -