Как получить имя активного SAVEPOINT в Informix - PullRequest
0 голосов
/ 04 февраля 2020

Есть ли способ в Informix (v12 или выше) получить имя текущего SAVEPOINT?

В Oracle есть что-то похожее: вы можете назвать транзакцию с помощью SET TRANSACTION NAME и затем выбрать имя транзакции от v$transaction:

SELECT name 
    FROM v$transaction
    WHERE xidusn
          || '.'
          || xidslot
          || '.'
          || xidsqn = DBMS_TRANSACTION.LOCAL_TRANSACTION_ID;

Это не очень просто, но это помогает. Фактически, мы можем использовать это, чтобы иметь переменную в области транзакции (да, это ужасно, но она работает годами).

У нас есть механизм, основанный на этом, и мы хотели бы перенести его на Informix. Есть способ сделать это?

Конечно, если есть другой механизм, обеспечивающий переменные в области транзакции (поэтому DEFINE GLOBAL - это не то, что мы ищем), это тоже было бы полезно, но я сомневаюсь, что он есть.

1 Ответ

0 голосов
/ 12 февраля 2020

Спасибо всем за ваши комментарии.

Позвольте мне показать решение, которое я придумала. Это просто идея в процессе разработки, но я надеюсь, что она приведет к чему-то: мне понадобится таблица «audit_lock», которая всегда содержит запись для текущей транзакции, содержащую информацию о текущей транзакции, особенно имя пользователя и уникальный идентификатор_транзакции (UUID) или похожие). Эта строка будет вставлена ​​при запуске транзакции и удалена перед ее фиксацией.

Затем у меня есть таблица generi c audit_trail, содержащая проверенную информацию.

Все проверенные таблицы заполняют шаблон c таблица контрольного журнала с использованием триггеров, сериализующая каждый проверенный столбец в отдельную запись общей таблицы c контрольного журнала.

Для таблицы Audit_lock и audit_trail необходимо использовать блокировку строк. Также, чтобы избежать блокировок чтения в таблице aud_lock, нам нужно установить уровень изоляции на COMMITTED READ LAST COMMITTED. Если ваш вариант использования не поддерживает это, предложенный шаблон не работает.

Вот DDL:

CREATE TABLE audit_lock
(
   transaction_id varchar(40) primary key,
   username varchar(40)
);

alter table audit_lock
lock mode(ROW);

CREATE TABLE audit_trail
(
   id       serial primary key,
   tablename varchar(255) NOT NULL,
   record_id numeric(10) NOT NULL,
   username varchar(40) NOT NULL,
   transaction_id varchar(40) NOT NULL,
   changed_column_name varchar(40),
   old_value varchar(40),
   new_value varchar(40),
   operation varchar(40) NOT NULL,
   operation_date datetime year to second NOT NULL
);

alter table audit_trail
lock mode(ROW);

Теперь нам нужно иметь проверенную таблицу:

CREATE TABLE audited_table
(
   id serial,
   somecolumn varchar(40)
);

И в таблице есть триггер вставки, записывающий в Audit_trail:

CREATE PROCEDURE proc_trigger_audit_audited_table () 
REFERENCING OLD AS o NEW AS n FOR audited_table;

INSERT INTO audit_trail
(
  tablename,
  record_id,
  username,
  transaction_id,
  changed_column_name,
  old_value,
  new_value,
  operation,
  operation_date
)
VALUES
(
  'audited_table',
  n.id,
  (SELECT username FROM audit_lock),
  (SELECT transaction_id FROM audit_lock),
  'somecolumn',
  '',
  n.somecolumn,
  'INSERT',
  sysdate
);

END PROCEDURE;

CREATE TRIGGER audit_insert_audited_table INSERT ON audited_table REFERENCING NEW AS post
  FOR EACH ROW(EXECUTE PROCEDURE proc_trigger_audit_audited_table() WITH TRIGGER REFERENCES);

Теперь давайте воспользуемся этим: Сначала вызывающей стороне транзакции необходимо сгенерировать для себя транзакцию_id, возможно, используя механизм генерации UUID. В приведенном ниже примере значениеaction_id просто равно «4711».

BEGIN WORK;

SET ISOLATION TO COMMITTED READ LAST COMMITTED; --should be set globally 

-- Issue the generation of the audit_lock entry at the beginnig of each transaction 
insert into audit_lock (transaction_id, username) values ('4711', 'userA');

-- Is it there?
select * from audit_lock;

-- do data manipulation stuff
insert into audited_table (somecolumn) values ('valueA');

-- Issue that at the end of each transaction 
delete from audit_lock
where transaction_id = '4711';

commit;

В быстром тесте все это работало даже в одновременных транзакциях. Конечно, это все еще требует большой работы и тестирования, но в настоящее время я надеюсь, что путь возможен.

Позвольте мне также добавить немного больше информации о другом подходе, который мы используем в Oracle: В Oracle мы (ab) используем имя транзакции, чтобы хранить именно ту информацию, которая в приведенном выше предложении хранится в таблице audit_lock.

Остальное - то же, что и выше. Триггеры отлично работают в этом конкретном приложении c, хотя, конечно, существует множество сценариев ios для других приложений, где установка триггеров вставки, удаления и обновления для каждой таблицы создает записи для каждого измененного столбца в таблице. быть сумасшедшим В нашем приложении оно отлично работает уже десять лет и не оказывает заметного влияния на производительность при использовании приложения.

На сервере приложений java все блоки кода, которые изменяют данные, начинаются с настройки сначала имя транзакции, а затем множество изменений в различных таблицах, которые могут вызывать все эти триггеры. Все они выполняются в одной и той же транзакции, и, поскольку она имеет имя транзакции, которое содержит пользователя приложения, триггеры могут записать эту информацию в таблицу контрольного журнала.

Я знаю, что существуют другие подходы к проблеме, и вы могли бы даже сделать это только с функциями гибернации, но наш подход позволяет нам обеспечить некоторую согласованность через базу данных (ограничение NOT NULL в таблице журнала аудита для имени пользователя). Поскольку все выполняется с помощью триггеров, мы можем позволить этим сбоям, если имя транзакции не содержит пользователя (требуя, чтобы оно было в указанном формате c). Если есть какие-либо другие части приложения, другие приложения или невежественные администраторы, пытающиеся выпускать обновления для проверенных таблиц без учета установки имени транзакции в указанном формате c, эти обновления завершатся неудачно. Это делает обновления проверяемых таблиц, которые не генерируют требуемые записи в таблице аудита, более трудными (конечно, не невозможными, конечно, недоброжелательный администратор может сделать что-либо). позвольте мне процитировать Луиса: может показаться ужасной идеей, но у меня есть свой вариант использования;)

Идея @ Luís создавать в каждой транзакции конкретную c таблицу для хранения информации вызывает проблему блокировки в systables. Давайте назовем это «таблица информации о транзакции». Эта идея не пришла мне в голову, поскольку DDL вызывает коммиты в Oracle. Поэтому я попытался сделать это в Informix, но если я попытаюсь создать таблицу с именем «tblX» в двух одновременных транзакциях, вторая транзакция получит исключение блокировки:

Cannot update system catalog (systables). [SQL State=IX000, DB Errorcode=-312] 
Next: ISAM error: key value locked [SQL State=IX000, DB Errorcode=-144]

Но разрешив всем транзакциям использовать ту же таблицу, что и выше работает, насколько я тестировал это прямо сейчас.

...