Понимание различий между таблицей и API транзакций - PullRequest
11 голосов
/ 22 июня 2010

Friends,

This Ask Tom thread , который я нашел через другой вопрос SO, упоминает Table и Transactional API, и я пытаюсь понять разницу между ними.

Table 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, - это метод, в котором запись извлекается из базы данных, т. Е. Вызов Select против PL / SQL?

Это так?или я совсем упустил суть?

Ответы [ 2 ]

16 голосов
/ 22 июня 2010

Давайте начнем с Table API. Это практика передачи доступа к таблицам через PL / SQL API. Итак, у нас есть пакет для каждой таблицы, который должен быть сгенерирован из словаря данных. В пакете представлен стандартный набор процедур выдачи DML для таблицы и некоторые функции для извлечения данных.

Для сравнения транзакционный API представляет собой единицу работы. Он вообще не предоставляет никакой информации о базовых объектах базы данных. Транзакционные 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 это намного проще:

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;
/

Так в чем же разница при получении данных? Поскольку подход Transactional 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);

... особенно если запись сотрудника имеет столбцы больших объектов.

Это также более эффективно, чем:

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

... если каждый из этих получателей выполняет отдельную инструкцию SELECT. Что не является неизвестным: это плохая ОО практика, которая приводит к ужасной производительности базы данных.

Сторонники API таблиц отстаивают их на основании того, что они защищают разработчика от необходимости думать о SQL. Люди, которые осуждают их, не любят API таблиц по той же причине . Даже лучшие API таблиц имеют тенденцию поощрять обработку RBAR. Если мы пишем собственный SQL каждый раз, мы с большей вероятностью выберем подход, основанный на множествах.

Использование транзакционных AP не обязательно исключает использование get_resultset() функций. API запросов по-прежнему имеет большую ценность. Но скорее всего он будет построен из представлений и функций, реализующих объединения, чем из SELECT для отдельных таблиц.

Между прочим, я думаю, что создание Transactional API поверх Table 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 не является ключевым для сотрудников.

Если честно, если у нас есть Table 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.

Если вы хотите исследовать использование Table APIs, лучше всего начать с Quest CodeGen Utility Стивена Фюрштайна (ранее QNXO).Это почти так же хорошо, как генераторы TAPI, и это бесплатно.

10 голосов
/ 22 июня 2010

Табличный API (TAPI) - это простой API, который предоставляет базовые операции CRUD для таблицы.Например, если у нас есть таблица 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) - это API, который работает на уровне транзакций, а не на уровне отдельных CRUD (хотя в некоторых случаях это будет то же самое).Например, 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;

Другие (например, Том Кайт и я) воспримут это как избыточное количество, не добавляя реального значения.Только XAPI (путь Тома Кайта) или XAPI, которые называют TAPI (способ Стива Фюрштайна).Но в некоторых системах есть только TAPI, что очень плохо - то есть они оставляют авторам пользовательского интерфейса возможность связывать вместе необходимые вызовы TAPI для выполнения транзакции.См. мой блог о последствиях такого подхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...