programing

Table과 Transaction API의 차이점 이해

yellowcard 2023. 9. 17. 12:13
반응형

Table과 Transaction API의 차이점 이해

친구들,

다른 SO 질문을 통해 찾은 이 질문 톰 스레드는 Table과 Transactional API에 대해 언급하고 있으며 이 둘의 차이점을 이해하려고 합니다.

TAPI(Table API)는 기본 테이블에 대한 액세스 권한이 없고 정보를 얻기 위한 "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 사이에서 볼 수 있는 유일한 차이점은 레코드를 데이터베이스에서 검색하는 방법, 즉 Select Versus a PL/SQL 호출입니까?

그거에요?아니면 내가 요점을 완전히 놓친 것일까요?

Table API부터 시작하겠습니다.이것은 PL/SQL API를 통해 테이블에 대한 접근을 중재하는 방법입니다.따라서, 우리는 데이터 사전에서 생성되어야 하는 테이블 당 패키지가 있습니다.패키지에는 테이블에 대한 DML 발행을 위한 표준 절차 세트와 데이터 검색을 위한 일부 기능이 제시되어 있습니다.

비교적으로 트랜잭션 API는 작업 단위를 나타냅니다.기본 데이터베이스 개체에 대한 정보를 전혀 노출하지 않습니다.트랜잭션 API는 더 나은 캡슐화와 더 깨끗한 인터페이스를 제공합니다.

그 대비는 이렇습니다.새 부서를 만들 때 다음과 같은 업무 규칙을 고려합니다.

  1. 새 부서에는 이름과 위치가 있어야 합니다.
  2. 새 부서에는 기존 직원인 관리자가 있어야 합니다.
  3. 기존의 다른 직원들은 새로운 부서로 옮길 수 있습니다.
  4. 새 부서에 새 직원이 배치될 수 있습니다.
  5. 새 부서에는 2명 이상의 직원이 할당되어 있어야 합니다(관리자 포함).

테이블 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);

...특히 직원 기록에 LOB 열이 있는 경우.

또한 다음보다 더 효율적입니다.

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

... 각 getter가 별도의 SELECT 문을 실행하는 경우.알려지지 않은 것은 아닙니다. 이는 잘못된 OO 관행으로 인해 데이터베이스 성능이 크게 저하됩니다.

표 API의 지지자들은 개발자가 SQL에 대해 생각할 필요가 없도록 보호한다는 근거로 표 API를 주장합니다.그들을 평가절하하는 사람들은 바로 같은 이유로 테이블 API를 싫어합니다.최고의 표 API조차도 RBAR 처리를 권장하는 경향이 있습니다.매번 SQL을 작성할 때마다 세트 기반 접근 방식을 선택할 가능성이 높습니다.

Transactional APis의 배제되는 것은 아닙니다.get_resultset() .질의하는 API에는 여전히 많은 가치가 있습니다.그러나 개별 테이블의 SELECT보다 보기와 조인을 구현하는 기능으로 구축될 가능성이 높습니다.

참고로, 테이블 API 위에 트랜잭션 API를 구축하는 것은 좋은 생각이 아닙니다. 우리는 여전히 세심하게 작성된 조인 대신 사일로화된 SQL 문을 가지고 있습니다.

예를 들어, 지역의 모든 직원의 급여를 업데이트하기 위한 트랜잭션 API의 두 가지 구현이 있습니다(지역은 조직의 대규모 섹션이며 부서는 지역에 할당됨).

첫 번째 버전은 순수 SQL만 없는 테이블 API 호출입니다. 이것은 Strawman이 아니라고 생각합니다. 테이블 API 패키지에서 본 일종의 기능을 사용합니다(일부는 SET_XXX() 프로시저가 아닌 동적 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;
    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에서는 지역별 직원을 선택하는 데 필요한 조인을 작성하는 것이 매우 쉬운 일이기 때문입니다.지역이 직원의 핵심이 아니기 때문에 표 API를 사용하는 것은 훨씬 어렵습니다.

공정하게 말하면 동적 SQL을 지원하는 테이블 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과 같은 다른 시스템에서 데이터 피드를 생성하거나 소비하는 것일 수 있습니다.

테이블 API의 사용을 조사하고 싶다면 Steven Feuerstein의 Quest CodeGen Utility(이전 QNXO)를 시작하는 것이 가장 좋습니다.이것은 TAPI 발전기가 얻을 수 있는 것과 맞먹으며, 무료입니다.

테이블 API(Table API)는 테이블에 대한 기본적인 CRUD 연산을 제공하는 간단한 API입니다.예를 들어, 우리가 테이블 R을 가지고 있다면,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가 있으며 모든 삽입, 업데이트 및 삭제가 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는 한 번의 삽입, 업데이트, 삭제를 수행할 수 없습니다.다음과 같은 작업을 수행할 수 있습니다.

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;

즉, 하나 또는 여러 개의 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;

다른 사람들(톰 카이트나 나 같은)은 이것이 실제 가치를 추가하지 않고 과잉 살상이라고 여길 것입니다.

따라서 XAPI를 단독으로 가질 수도 있고(Tom Kyte 방식), TAPI를 부르는 XAPI를 가질 수도 있습니다(Steve Feuerstein 방식).그러나 일부 시스템에는 TAPI만 있는 경우가 있는데, 이는 매우 열악한 문제입니다. 즉, 트랜잭션을 구성하기 위해 필요한 TAPI 호출을 함께 연결하도록 사용자 인터페이스 작성자에게 맡깁니다.이러한 접근 방식의 의미에 대해서는 제 블로그를 참조하십시오.

언급URL : https://stackoverflow.com/questions/3092041/understanding-the-differences-between-table-and-transaction-apis

반응형