温馨提示×

Linux Oracle触发器使用案例

小樊
45
2025-09-27 11:40:17
栏目: 云计算

Linux环境下Oracle触发器使用案例

1. 语句级触发器:禁止非工作时间插入员工数据

场景:企业规定仅能在工作日(周一至周五)8:00-18:00录入新员工信息,需通过触发器强制约束。
案例代码

CREATE OR REPLACE TRIGGER trg_restrict_emp_insert
BEFORE INSERT ON employees
DECLARE
  v_day   VARCHAR2(10);
  v_hour  NUMBER;
BEGIN
  -- 获取当前星期几(1-7,1=周日)
  v_day := TO_CHAR(SYSDATE, 'DY');
  -- 获取当前小时(24小时制)
  v_hour := TO_NUMBER(TO_CHAR(SYSDATE, 'HH24'));
  
  -- 检查是否为周末或非工作时间
  IF v_day IN ('SAT', 'SUN') OR v_hour < 8 OR v_hour >= 18 THEN
    RAISE_APPLICATION_ERROR(-20001, '非工作时间(周末/8:00-18:00外)禁止插入员工数据!');
  END IF;
END;
/

说明:此触发器为BEFORE STATEMENT类型(默认),在employees表插入操作前执行,通过RAISE_APPLICATION_ERROR阻止非法操作。

2. 行级触发器:工资调整合法性检查

场景:员工涨工资时,新工资不能低于原工资(避免误操作),且部门平均工资不能超过公司规定的阈值(如10000元)。
案例代码

CREATE OR REPLACE TRIGGER trg_salary_check
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
DECLARE
  v_dept_avg_sal NUMBER;
BEGIN
  -- 检查新工资是否低于原工资
  IF :NEW.salary < :OLD.salary THEN
    RAISE_APPLICATION_ERROR(-20002, '新工资不能低于原工资(原工资:' || :OLD.salary || ')!');
  END IF;
  
  -- 计算所属部门的平均工资
  SELECT AVG(salary)
  INTO v_dept_avg_sal
  FROM employees
  WHERE department_id = :NEW.department_id;
  
  -- 检查部门平均工资是否超过阈值
  IF v_dept_avg_sal > 10000 THEN
    RAISE_APPLICATION_ERROR(-20003, '部门(' || :NEW.department_id || ')平均工资已超过10000元,无法调整!');
  END IF;
END;
/

说明:此触发器为BEFORE ROW类型,对employees表的salary列修改(插入或更新)逐行检查,使用:OLD(原值)和:NEW(新值)伪记录变量实现数据验证。

3. 数据审计触发器:记录员工工资变更日志

场景:需跟踪员工工资的变更历史(包括变更人、时间、新旧工资),便于后续审计。
案例代码

-- 1. 创建审计日志表
CREATE TABLE emp_salary_audit (
  audit_id      NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  emp_id        NUMBER,
  old_salary    NUMBER,
  new_salary    NUMBER,
  change_date   TIMESTAMP DEFAULT SYSTIMESTAMP,
  changed_by    VARCHAR2(30) DEFAULT USER
);

-- 2. 创建触发器
CREATE OR REPLACE TRIGGER trg_emp_salary_audit
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
  -- 将变更记录插入审计表
  INSERT INTO emp_salary_audit (emp_id, old_salary, new_salary, changed_by)
  VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, USER);
END;
/

说明:此触发器为AFTER ROW类型,在employeessalary列更新后执行,将变更信息插入emp_salary_audit表,实现完整的变更轨迹记录。

4. 级联操作触发器:自动同步部门员工数量

场景employees表的department_id变更(如员工调岗)时,需自动更新对应departments表的employee_count(部门员工数),保持数据一致性。
案例代码

-- 1. 确保departments表有employee_count字段
ALTER TABLE departments ADD (employee_count NUMBER DEFAULT 0);

-- 2. 创建触发器
CREATE OR REPLACE TRIGGER trg_sync_dept_employee_count
AFTER INSERT OR DELETE OR UPDATE OF department_id ON employees
FOR EACH ROW
BEGIN
  -- 插入新员工:增加部门员工数
  IF INSERTING THEN
    UPDATE departments
    SET employee_count = employee_count + 1
    WHERE department_id = :NEW.department_id;
  -- 删除员工:减少部门员工数
  ELSIF DELETING THEN
    UPDATE departments
    SET employee_count = employee_count - 1
    WHERE department_id = :OLD.department_id;
  -- 更新部门ID:减少原部门数,增加新部门数
  ELSIF UPDATING THEN
    UPDATE departments
    SET employee_count = employee_count - 1
    WHERE department_id = :OLD.department_id;
    
    UPDATE departments
    SET employee_count = employee_count + 1
    WHERE department_id = :NEW.department_id;
  END IF;
END;
/

说明:此触发器为AFTER ROW类型,覆盖employees表的插入、删除、更新(department_id列)操作,通过IF-ELSIF分支实现不同场景下的部门员工数同步。

5. 系统触发器:审计用户登录行为

场景:需记录所有用户的登录和注销时间,便于监控数据库访问安全。
案例代码

-- 1. 创建登录日志表
CREATE TABLE user_login_audit (
  log_id        NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  username      VARCHAR2(30),
  action        VARCHAR2(10), -- 'LOGIN' 或 'LOGOUT'
  action_time   TIMESTAMP DEFAULT SYSTIMESTAMP,
  ip_address    VARCHAR2(50)
);

-- 2. 创建登录触发器
CREATE OR REPLACE TRIGGER trg_log_user_login
AFTER LOGON ON DATABASE
BEGIN
  INSERT INTO user_login_audit (username, action, ip_address)
  VALUES (USER, 'LOGIN', SYS_CONTEXT('USERENV', 'IP_ADDRESS'));
END;
/

-- 3. 创建注销触发器
CREATE OR REPLACE TRIGGER trg_log_user_logout
BEFORE LOGOFF ON DATABASE
BEGIN
  INSERT INTO user_login_audit (username, action, ip_address)
  VALUES (USER, 'LOGOUT', SYS_CONTEXT('USERENV', 'IP_ADDRESS'));
END;
/

说明:此触发器为SYSTEM类型,分别监听AFTER LOGON(登录)和BEFORE LOGOFF(注销)事件,记录用户操作及IP地址,提升数据库安全性。

注意事项

  • 性能优化:避免在触发器中执行复杂查询或大量DML操作,防止拖慢数据库性能。
  • 权限控制:触发器执行时需具备相应权限(如访问其他表的权限),建议通过角色而非直接授权给用户。
  • 错误处理:使用RAISE_APPLICATION_ERROR抛出明确错误信息,便于排查问题;避免静默失败导致数据不一致。
  • 测试验证:在生产环境部署前,需在测试环境充分测试触发器逻辑,确保不会引发意外副作用(如死循环、锁表)。

0