2010-06-22 23 views
11

朋友,了解表和事务API的

this向汤姆thread我通过另一个SO问题发现,之间的差异提到表和事务API的,我试图了解它们之间的区别。

表API(TAPI)是没有访问基础表的地方,并且有“获取者”设置者来获取信息。

例如选择一个地址我想:

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调用?

是吗?还是我完全错过了这一点?

回答

15

让我们从表格API开始。这是通过PL/SQL API调解对表的访问的做法。所以,我们为每个表提供一个包,它应该从数据字典中生成。该软件包提供了一套针对表格发布DML的标准程序和用于检索数据的一些功能。

通过比较,Transactional API表示一个Unit Of Work。它根本不公开有关底层数据库对象的任何信息。事务性API提供了更好的封装和更清晰的接口。

对比就是这样。考虑到这些业务规则用于创建一个新的部门:

  1. 新的部门必须有一个名称和位置
  2. 新的部门必须有一个经理,谁必须是现有员工
  3. 其他现有员工可能转移到新的部门
  4. 新员工可能被分配到新部门
  5. 新的部门必须指派至少两名员工(包括管理者)

使用表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就简单得多:

​​

那么,为什么在检索数据的区别?由于事务性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); 

。特别是如果员工记录具有LOB列。

它也比更高效:

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

...如果每个这些getter执行一个单独的SELECT语句。这不是未知数:这是一个糟糕的OO操作,导致可怕的数据库性能。

表API的支持者认为,他们的基础是他们屏蔽了开发人员不需要考虑SQL。贬低他们的人不喜欢表API 出于同样的原因。即使是最好的Table API也倾向于鼓励RBAR处理。如果我们每次编写自己的SQL都更有可能选择基于集合的方法。

使用交易型AP并不一定排除使用get_resultset()函数。在查询API中仍然有很多价值。但它更可能是由实现联接的视图和函数构建的,而不是个别表上的SELECT。顺便提一句,我认为在表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中,编写我们需要按区域选择Employees的连接是一件很简单的事情。使用Table API要困难得多,因为Region不是Employees的关键。

为了公平起见,如果我们有一个表API,它支持动态SQL,事情更好,但仍不理想:

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。

如果你想调查表API的使用,最好的开始是Steven Feuerstein的Quest CodeGen Utility(以前称为QNXO)。这与TAPI生成器一样好,而且它是免费的。

+0

+1非常好! – 2010-06-22 11:26:17

+0

@APC感谢您的全面而清晰的回应。我可以请你扩大你最后一段的内容吗? “顺便说一下,我认为通过Table API构建事务API并不是一个好主意:我们仍然拥有孤立的SQL语句,而不是仔细编写的连接。”我已经读了两遍,得出了两个不同的结论(这是我的错,不是你的),我只是想澄清这一点! – 2010-06-22 12:33:50

+0

+1优秀答案 – 2010-06-22 12:38:20

9

表API(TAPI)是一个简单的API,为表提供基本的CRUD操作。例如,如果我们有一个tableR MYTABLE (id INTEGER PRIMARY KEY, text VACHAR2(30)),那么TAPI会是这样的:

package mytable_tapi is 
    procedure create_rec (p_id integer, p_text varchar2); 
    procedure update_rec (p_id integer, p_text varchar2); 
    procedure delete_rec (p_id integer); 
    function get_rec (p_id integer) returns mytable%rowtype; 
end; 

当您使用塔皮斯,每个表都有一个TAPI,每个插入,更新和删除通过TAPI去。

交易API(XAPI)是一种在交易层面而不是在单独的CRUD层面工作的API(尽管在一些的情况下这将是相同的事情)。例如,XAPI来处理银行交易可能是这个样子:

package banking_xapi is 
    procedure make_transfer (p_from_account integer, p_to_account integer, 
          p_amount number); 
    ... -- other XAPI procs 
end; 

的make_transfer过程可能无法执行单一插入,更新或删除。它可以做这样的事情:

procedure make_transfer (p_from_account integer, p_to_account integer, 
         p_amount number) 
is 
begin 
    insert into transfer_details (from_account, to_account, amount) 
     values (p_from_account, p_to_account, p_amount); 

    update accounts set balance = balance-p_amount 
    where account_no = p_from_account; 

    update accounts set balance = balance+p_amount 
    where account_no = p_to_account; 
end; 

即它执行的整个事务,它可以由1个或数DML语句。

TAPI的支持者会说,这是编码错误的,应该不包含DML,而是调用TAPI代码,如:

procedure make_transfer (p_from_account integer, p_to_account integer, 
         p_amount number) 
is 
begin 
    transactions_tapi.insert_rec (p_from_account, p_to_account, p_amount); 

    accounts_tapi.update_rec (p_from_account, -p_amount); 

    accounts_tapi.update_rec (p_to_account, p_amount); 
end; 

其他(如Tom Kyte和我自己)会认为这是矫枉过正,不加真正的价值。

因此,您可以单独使用XAPI(Tom Kyte的方式),或者称为TAPI的XAPI(Steve Feuerstein的方式)。但是一些系统仅具有TAPI,这是真的很差 - 即它们将它留给用户界面的编写者以串联必要的TAPI调用以组成事务。请参阅my blog了解该方法的含义。

+0

+1谢谢Tony的回复 – 2010-06-22 12:35:35