gpt4 book ai didi

oracle - 了解 Table 和 Transaction API 之间的区别

转载 作者:行者123 更新时间:2023-12-01 23:19:17 26 4
gpt4 key购买 nike

friend 们,

这问汤姆 thread我通过另一个 SO 问题发现,提到了 Table 和 Transactional API,我试图了解它们之间的区别。

表 API (TAPI) 是无法访问底层表的地方,并且有“getter”和“setter”来获取信息。

例如要选择一个地址,我会:

   the_address := get_address(address_id);

代替:
   select the_address
from some_table
where identifier = address_id

然后要更改地址,我将调用另一个负责更改的 TAPI:
   ...
change_address(address_id, new_address);
...

事务 API (XAPI) 再次是无法直接访问修改表中的信息但我可以从中进行选择的地方? (这是我的理解有点模糊的地方)

要选择一个地址,我会:
   select the_address
from some_table
where identifier = address_id

然后改变它我会打电话
   ...
change_address(address_id, new_address);
...

所以我能看到的 TAPI 和 XAPI 之间的唯一区别是从数据库中检索记录的方法,即选择与 PL/SQL 调用?

是这样吗?还是我完全没有捕获重点?

最佳答案

让我们从 Table API 开始。这是通过 PL/SQL API 调解对表的访问的做法。所以,我们每个表都有一个包,它应该从数据字典中生成。该包提供了一组标准的程序,用于针对表发出 DML,以及一些用于检索数据的函数。

相比之下,事务 API 代表一个工作单元。它根本不公开有关底层数据库对象的任何信息。事务 API 提供更好的封装和更清晰的界面。

对比是这样的。考虑以下创建新部门的业务规则:

  • 新部门必须有名称和位置
  • 新部门必须有经理,经理必须是现有员工
  • 其他现有员工可能会转移到新部门
  • 新员工可能被分配到新部门
  • 新部门必须至少分配两名员工(包括经理)

  • 使用 Table API,事务可能如下所示:
    DECLARE
    dno pls_integer;
    emp_count pls_integer;
    BEGIN
    dept_utils.insert_one_rec(:new_name, :new_loc, dno);
    emp_utils.update_one_rec(:new_mgr_no ,p_job=>'MGR’ ,p_deptno=>dno);
    emp_utils.update_multi_recs(:transfer_emp_array, p_deptno=>dno);
    FOR idx IN :new_hires_array.FIRST..:new_hires_array.LAST LOOP
    :new_hires_array(idx).deptno := dno;
    END LOOP;
    emp_utils.insert_multi_recs(:new_hires_array);
    emp_count := emp_utils.get_count(p_deptno=>dno);
    IF emp_count < 2 THEN
    raise_application_error(-20000, ‘Not enough employees’);
    END IF;
    END;
    /

    而使用事务 API 则要简单得多:
    DECLARE
    dno subtype_pkg.deptno;
    BEGIN
    dept_txns.create_new_dept(:new_name
    , :new_loc
    , :new_mgr_no
    , :transfer_emps_array
    , :new_hires_array
    , dno);
    END;
    /

    那么为什么在检索数据时会有不同呢?因为事务 API 方法不鼓励通用 get()函数以避免盲目使用低效的 SELECT 语句。

    例如,如果您只想要员工的薪水和佣金,则查询此 ...
    select sal, comm
    into l_sal, l_comm
    from emp
    where empno = p_eno;

    ......比执行这个更好......
    l_emprec := emp_utils.get_whole_row(p_eno);

    ...特别是如果 Employee 记录有 LOB 列。

    它也比:
    l_sal := emp_utils.get_sal(p_eno);
    l_comm := emp_utils.get_comm(p_eno);

    ...如果这些 getter 中的每一个都执行单独的 SELECT 语句。众所周知:这是一种糟糕的 OO 实践,会导致糟糕的数据库性能。

    Table API 的支持者为他们辩护,理由是它们使开发人员无需考虑 SQL。出于同样的原因,弃用它们的人不喜欢 Table API。即使是最好的 Table API 也倾向于鼓励 RBAR 处理。如果我们每次都编写自己的 SQL,我们更有可能选择基于集合的方法。

    使用事务性 API 并不一定排除使用 get_resultset()职能。查询 API 仍有很多值(value)。但它更有可能是由实现连接的 View 和函数构建的,而不是单个表上的 SELECT。

    顺便说一句,我认为在 Table API 之上构建事务 API 不是一个好主意:我们仍然使用孤立的 SQL 语句而不是精心编写的连接。

    例如,这里有两个不同的事务 API 实现,用于更新区域中每个员工的工资(区域是组织的一个大型部分;部门被分配到区域)。

    第一个版本没有纯 SQL,只有 Table API 调用,我不认为这是一个稻草人:它使用了我在 Table API 包中看到的那种功能(尽管有些使用动态 SQL 而不是命名的 SET_XXX() 过程) .
    create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
    , p_sal_adjustment in number )
    as
    emps_rc sys_refcursor;
    emp_rec emp%rowtype;
    depts_rc sys_refcursor;
    dept_rec dept%rowtype;
    begin
    depts_rc := dept_utils.get_depts_by_region(p_region);

    << depts >>
    loop
    fetch depts_rc into dept_rec;
    exit when depts_rc%notfound;
    emps_rc := emp_utils.get_emps_by_dept(dept_rec.deptno);

    << emps >>
    loop
    fetch emps_rc into emp_rec;
    exit when emps_rc%notfound;
    emp_rec.sal := emp_rec.sal * p_sal_adjustment;
    emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
    end loop emps;

    end loop depts;

    end adjust_sal_by_region;
    /

    SQL 中的等效实现:
    create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
    , p_sal_adjustment in number )
    as
    begin
    update emp e
    set e.sal = e.sal * p_sal_adjustment
    where e.deptno in ( select d.deptno
    from dept d
    where d.region = p_region );
    end adjust_sal_by_region;
    /

    这比以前版本的嵌套游标循环和单行更新要好得多。这是因为在 SQL 中,编写我们需要按区域选择员工的连接是轻而易举的。使用 Table API 要困难得多,因为 Region 不是Employees 的键。

    公平地说,如果我们有一个支持动态 SQL 的 Table API,事情会更好但仍然不理想:
    create or replace procedure adjust_sal_by_region
    (p_region in dept.region%type
    , p_sal_adjustment in number )
    as
    emps_rc sys_refcursor;
    emp_rec emp%rowtype;
    begin
    emps_rc := emp_utils.get_all_emps(
    p_where_clause=>'deptno in ( select d.deptno
    from dept d where d.region = '||p_region||' )' );

    << emps >>
    loop
    fetch emps_rc into emp_rec;
    exit when emps_rc%notfound;
    emp_rec.sal := emp_rec.sal * p_sal_adjustment;
    emp_utils.set_sal(emp_rec.empno, emp_rec.sal);
    end loop emps;

    end adjust_sal_by_region;
    /

    最后一句话

    话虽如此,在某些情况下,表 API 可能很有用,当我们只想以相当标准的方式与单个表进行交互的情况下。一个明显的案例可能是从其他系统生成或使用数据馈送,例如ETL。

    如果您想研究 Table API 的使用,最好的起点是 Steven Feuerstein 的 Quest CodeGen Utility (原 QNXO)。这和 TAPI 生成器一样好,而且是免费的。

    关于oracle - 了解 Table 和 Transaction API 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3092041/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com