2010-06-22 50 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