Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / DB2: legacy app / 14 сообщений из 14, страница 1 из 1
08.06.2005, 20:18
    #33108143
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
день добрый, DBAs.

Имеем ситуацию -- в одном банке есть legacy приложение, которое, понятно, процессит денежки. Приложение это написано на Java (а ранее было написано на C), а моя задача -- дописывая и переписывая функциональность по кусочку, постепенно снять его с эксплуатации, поскольку с поддержкой большие проблемы. Дописываемая функциональность живет в отдельном приложении, в другом процессе, на другом сервере. При этом дописывать нужно по возможности поверх существующей DB schema, и крайне нежелательно трогать что-либо в legacy (хотя и возможно) -- нет regression tests.

Итак, проблема -- для функциональности, которую я сейчас разрабатываю, необходимо создавать записи в существующей таблице. В таблице есть суррогатный primary key, который мне при вставке записи необходимо сгенерить (там не используются IDENTITY и SEQUENCE ввиду древности приложения). Ключ в legacy приложении генерится так -- существует таблица вида ( name varchar(30), max_id integer ), которой делается

1. SELECT max_id from ... where name='tableName'
2. increment max_id
3. UPDATE ... SET max_id = ... where name='tableName'

Для пущей важности всё это еще обложено Java synchronized, чтобы избежать duplicate key.

Мне надо определиться, как я буду генерить ключи. До сего момента я думал, что буду делать SELECT ... FOR UPDATE, полагаясь на блокировки DB2. Однако, попробовав на макете, понял, что это не работает. Legacy делает свой select в READ COMMITTED transaction, и в ситуации:

Код: plaintext
1.
2.
3.
4.
5.
LEGACY     ME
SELECT    
               SELECT FOR UPDATE
INCREMENT
UPDATE

получаем duplicate key в legacy и у меня. Попробовал выставить себе
FOR UPDATE WITH RS USE AND KEEP UPDATE LOCKS
Не особо помогает. Всё равно существует ситуация, когда мы получаем равные ключи. Подъем моей транзакции до SERIALIZED также не помогает.

Работает только вариант, когда исходный код legacy подправлен на предмет
добавления FOR UPDATE WITH RS USE AND KEEP UPDATE LOCKS. В этом случае дубликатов нет, но появляются deadlocks (кто бы сомневался).


Скажите мне -- существует ли способ залочить таблицу или запись так, чтобы
а) если кто-то выполнил SELECT на таблице, то мой лок ждал бы его COMMIT'а?
б) если я получил лок, то никто не смог бы сделать SELECT до моего COMMIT?

P.S. думал переписать таки legacy под SEQUENCES, но -- страшно, и они в одном месте выделяют сразу пачку ID, что с SEQUENCES, AFAIK, невозможно?

P.P.S. DB2 8.x (8.1?)
...
Рейтинг: 0 / 0
09.06.2005, 11:03
    #33108799
Alexander Mozhaev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Vladimir Dyuzhevдень добрый, DBAs.
...

Скажите мне -- существует ли способ залочить таблицу или запись так, чтобы
а) если кто-то выполнил SELECT на таблице, то мой лок ждал бы его COMMIT'а?
б) если я получил лок, то никто не смог бы сделать SELECT до моего COMMIT?

P.S. думал переписать таки legacy под SEQUENCES, но -- страшно, и они в одном месте выделяют сразу пачку ID, что с SEQUENCES, AFAIK, невозможно?

P.P.S. DB2 8.x (8.1?)

перед селектом:
lock table ... in exclusive mode
...
Рейтинг: 0 / 0
09.06.2005, 11:49
    #33108984
ggv
ggv
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
и неясно про sequence и выделение пачкой. Это не то, что в sequence делает кэширование
...
Рейтинг: 0 / 0
09.06.2005, 13:23
    #33109318
nkulikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Какая версия DB2???
В 8-ке можно сделать следующее

То что имеешь ты в lеgacy приложении

Получить № следующего заказа
Код: plaintext
1.
SELECT nextnum FROM ordermeta;			 1  I/O, S
Увеличить номер следующего заказа #
Код: plaintext
1.
2.
UPDATE ordermeta               			 1  I/O
   SET nextnum = nextnum +  1 ;	                S->X 
Вставить новый заказ
Код: plaintext
1.
INSERT INTO orders VALUES(nextnum, ...);	 1  I/O
Возвратить nextnum клиенту

Имеем Deadlock, 3 SQL оператора, 3 I/O, одна строка

OLTP Mantra гласит


Уменьшение кол-ва вызовов (Reduce Codepath)

Уменьшение Logical I/O

Уменьшение Physical I/O

Минимизация влияния блокировок

Избежание Deadlocks

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
WITH inco AS (SELECT ordernum 
                FROM OLD TABLE(UPDATE ordermeta 
                                  SET ordernum 
                                    = ordernum +  1 ))
SELECT ordernum INTO :ordernum 
  FROM NEW TABLE(INSERT INTO orders 
                  SELECT ordernum, ... FROM inco);
No Deadlock, 2 I/O, 1 SQL Stmt, set oriented

Если можно было бы делать sequence, то было бы можно сделать проще

Код: plaintext
1.
2.
3.
4.
SELECT FROM INSERT 
SELECT ordernum INTO :ordernum
FROM NEW TABLE(INSERT INTO orders 
               VALUES(NEXT VALUE FOR orderseq, ...));
No Deadlock, 1 I/O,1 SQL Stmt, set oriented
...
Рейтинг: 0 / 0
09.06.2005, 17:31
    #33110265
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Alexander Mozhaev
перед селектом:
lock table ... in exclusive mode

не, не получается. вот обломившийся сценарий:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
SEQUENCE:  0   0   1   0   0   1   1   1 
BEGIN
SELECT
ID: 20 
          BEGIN
          LOCK
UPDATE
ID++: 21 
          SELECT
          ID: 20 
          UPDATE
          ID++: 21 
          COMMIT
COMMIT
java.lang.IllegalStateException: DUPLICATE KEYS: 21 
        at Main.processSequence(Main.java: 53 )
        at Main.main(Main.java: 10 )

слева -- legacy, справа -- я.
то есть -- legacy начинает транзакцию, делает выборку, потом я начинаю транзакцию, накладываю лок, legacy инкрементит и пытается обновить, но повисает, я вытаскиваю текущее значение -- а оно всё еще 20 -- увеличиваю, коммичу, освобождая тем самым таблицу, и после этого успешно проходит коммит от legacy. результат -- оба имеем ID=21.
...
Рейтинг: 0 / 0
09.06.2005, 17:36
    #33110291
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
чтобы точно показать, что я там делаю:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
BEGIN
SELECT ID FROM DOZEN.CONFLICT WHERE NAME='FOO'
GOT ID: 44 
                                                  BEGIN
                                                  LOCK TABLE DOZEN.CONFLICT IN EXCLUSIVE MODE
UPDATE DOZEN.CONFLICT SET ID=? WHERE NAME='FOO'
GONNA SET ID TO: 45 
                                                  SELECT ID FROM DOZEN.CONFLICT WHERE NAME='FOO' FOR UPDATE WITH RS USE AND KEEP UPDATE LOCKS
                                                  GOT ID: 44 
                                                  UPDATE DOZEN.CONFLICT SET ID=? WHERE NAME='FOO'
                                                  GONNA SET ID TO: 45 
                                                  COMMIT
COMMIT
java.lang.IllegalStateException: DUPLICATE KEYS: 45 
...
Рейтинг: 0 / 0
09.06.2005, 17:40
    #33110304
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
ggv
и неясно про sequence и выделение пачкой. Это не то, что в sequence делает кэширование

Не, это возможность прирастить счетчик за один вызов на N единиц, причем так, чтобы никто не вклинился в середину. Т.е. UPDATE ... SET ID = ID+10, например.
Legacy использует это для одного своего загадочного модуля, и пока неясно, необходимо ли иметь строго непрерывные ID, или это просто деталь реализации.
...
Рейтинг: 0 / 0
09.06.2005, 17:51
    #33110344
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
nkulikov
Какая версия DB2???
В 8-ке можно сделать следующее


Да, 8.


nkulikov
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
WITH inco AS (SELECT ordernum 
                FROM OLD TABLE(UPDATE ordermeta 
                                  SET ordernum 
                                    = ordernum +  1 ))
SELECT ordernum INTO :ordernum 
  FROM NEW TABLE(INSERT INTO orders 
                  SELECT ordernum, ... FROM inco);


Ух! Это пока за пределами моего понимания. Что тут происходит?
Я вообще не врубаюсь, какие-такие OLD TABLE, NEW TABLE... :(

Я адаптировал эту китайскую грамоту для моего теста, и получилось вот что:

Код: plaintext
1.
2.
WITH inco AS (SELECT ID,NAME FROM OLD TABLE (UPDATE DOZEN.CONFLICT SET ID = ID +  1 ))
SELECT ID,NAME FROM NEW TABLE(INSERT INTO DOZEN.CONFLICT SELECT ID,NAME FROM inco);

Этот код должен выполняться на моей стороне? Или на обоих? Явные блокировки нужны? Исполнение в Control Center приводит к выводу текущего значения, но не к обновлению такового... что я делаю не так?
...
Рейтинг: 0 / 0
09.06.2005, 17:55
    #33110358
ggv
ggv
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
ну insert в conflict тебе наверное не нужен
а чтоб понят это предложение попроси у Николая презентацию "Unleashed SQL"
Ну или читать доку
...
Рейтинг: 0 / 0
09.06.2005, 18:17
    #33110408
Vladimir Dyuzhev
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
nkulikov
WITH inco AS (SELECT ordernum
...


Наконец-то до меня дошло. Вот моя новая адаптация, которая работает просто perfectly.

Код: plaintext
1.
WITH inco AS (SELECT ID,NAME FROM OLD TABLE (UPDATE DOZEN.CONFLICT SET ID = ID +  1 )) SELECT ID FROM inco

Я так понимаю, её надо гонять на обоих сторонах -- и на legacy, и на replacer app. Ну... не хотелось менять legacy code, но, видать этого не избежать. Инкремент в один запрос сильно упрощает тамошний код, а то, что нет deadlocks (я проверил -- прогнал 70 возможных сценариев ;) ) -- вообще замечательно.

Искреннее нечеловеческое спасибо. Будем внедрять.
...
Рейтинг: 0 / 0
09.06.2005, 18:55
    #33110472
nkulikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Все таки я выложу эту презентацию на www.idug.ru
что бы все не рассылать,

несколко вырезок из нее


OLD TABLE промежуточная таблица как в триггерах
Для
DELETE

UPDATE
Просмотр оригинальных значения перед модификацией
Код: plaintext
1.
SELECT c1 FROM OLD TABLE(UPDATE T SET c1 =  10 )

NEW TABLE промежуточная таблица как в триггерах
Для

INSERT

UPDATE
Можно просмотреть

Значения вычисленные пользователем

IDENTITY

Что выставил триггер BEFORE

Генерируемые столбцы
Код: plaintext
1.
SELECT c1 FROM NEW TABLE(UPDATE T SET c1 = -c1)

FINAL TABLE
Содержимое после проверки RI и отработки AFTER триггера
Не разрешаются конфликты на изменяющейся (mutating) Талице

Пример
2 Таблицы Emp и Mgr
Транзакция повышение сотрудника
1) Удалить из сотрудников (Delete Emp)
2) Вставить в таблицу менеджеры (Insert Mgr)
2) Увеличить зарплату по умолчанию
4) Назначить бонус через триггер

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
CREATE TABLE emp (eid    INT NOT NULL PRIMARY KEY, 
                  salary INT NOT NULL);

CREATE TABLE mgr (eid    INT NOT NULL PRIMARY KEY,
                  salary INT NOT NULL,
                  bonus  INT NOT NULL);

CREATE TRIGGER iMgr 
 NO CASCADE BEFORE INSERT ON mgr 
 REFERENCING NEW AS n
 FOR EACH ROW
 SET n.bonus = coalesce(n.bonus, salary *  0 . 1 );


INSERT INTO emp VALUES( 1234 ,  50000 );

WITH del AS (SELECT salary, eid
               FROM OLD TABLE(DELETE FROM emp 
                               WHERE eid =  1234 )),
     ins AS (SELECT salary, old_salary, bonus, eid 
               FROM NEW TABLE (INSERT INTO 
                                mgr(eid, salary)  
                                INCLUDE (old_salary INT)
                                SELECT eid, 
                                       salary *  1 . 05 ,
                                       salary 
                                  FROM del))
SELECT eid, old_salary, salary, bonus FROM ins;

EID         OLD_SALARY  SALARY      BONUS      
----------- ----------- ----------- -----------
        1234         50000         52500          5250 
...
Рейтинг: 0 / 0
10.06.2005, 11:57
    #33111464
gardenman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Так - между прочим...
1) Реализовать аналог SEQUENCE элементарно в любой версии DB2 с помощью хранимых процедур.
2) При таком подходе можно также получать сразу пачку уникальных значений.
(Хотя я полагаю с SEQUENCE такое тоже возможно)
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
06.10.2006, 06:37
    #34036350
DPH3
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
nkulikovВсе таки я выложу эту презентацию на www.idug.ru
что бы все не рассылать,

Выложил или забыл?
...
Рейтинг: 0 / 0
06.10.2006, 10:47
    #34036805
Nikolay Kulikov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
DB2: legacy app
Я не забыл. Должно лежать я отдавал на публикацию. Если нет то постараюсь на следующей неделе.
...
Рейтинг: 0 / 0
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / DB2: legacy app / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]