PLSQL jobs表触发变异错误,使用内存缓存包仍无法解决
问题根因与修复方案
核心错误原因
你遇到的持续报错本质是两处代码逻辑仍在触发展变异状态的jobs表查询,并未真正用到你设计的内存缓存能力:
emp_pkg.SET_SALARY中存在完全冗余的FOR i IN (SELECT * FROM jobs)循环,这行代码直接查询了正在执行DML的变异表,且逻辑无意义——循环多少次就会重复执行多少次完全相同的UPDATE employees语句。- 你设计的
jobs_pkg缓存完全没有发挥作用:包内的get_minsalary/get_maxsalary函数仍然读取物理jobs表而非你加载到内存的jobstab集合;同时行级触发器init_jobpkg_trg每更新一行就会调用initialize全表查询jobs,这步操作本身就会触发变异表错误,性能也极差。
修复步骤
1. 修正emp_pkg冗余逻辑
删除多余的jobs表查询循环:
CREATE OR REPLACE PACKAGE BODY emp_pkg IS PROCEDURE SET_SALARY(pjobid jobs.job_id%type, psal jobs.min_salary%type) IS BEGIN UPDATE employees SET salary = psal WHERE job_id = pjobid; END SET_SALARY; END emp_pkg; /
仅这一步修改后,你原有逻辑就已经不会触发变异表错误——触发器执行过程中不再查询jobs表,不需要额外的缓存包也能正常运行。
2. (可选)修正jobs_pkg缓存逻辑
如果你需要保留内存缓存能力,修改包内函数直接读取内存集合,不再查询物理表:
CREATE OR REPLACE PACKAGE BODY jobs_pkg IS TYPE jobs_tab_type IS TABLE OF jobs%rowtype INDEX BY jobs.job_id%type; jobstab jobs_tab_type; PROCEDURE initialize IS BEGIN FOR rec IN (SELECT * FROM jobs) LOOP jobstab(rec.job_id) := rec; END LOOP; END; FUNCTION get_minsalary(p_jobid VARCHAR2) RETURN NUMBER IS BEGIN RETURN jobstab(p_jobid).min_salary; END get_minsalary; FUNCTION get_maxsalary(p_jobid VARCHAR2) RETURN NUMBER IS BEGIN RETURN jobstab(p_jobid).max_salary; END get_maxsalary; END jobs_pkg; /
同时将行级初始化触发器改为语句级触发器,避免变异表问题,也降低性能开销:
DROP TRIGGER init_jobpkg_trg; CREATE OR REPLACE TRIGGER init_jobpkg_trg BEFORE UPDATE OR INSERT ON jobs BEGIN jobs_pkg.initialize; END init_jobpkg_trg; /
内容的提问来源于stack exchange,提问作者Elijah Leis
相关产品推荐
相关产品推荐

