## 使用触发器在 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;
```

如果待删除的记录中包含默认配置，则不允许删除。