powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PowerBuilder [игнор отключен] [закрыт для гостей] / блокировка таблицы при insert
43 сообщений из 43, показаны все 2 страниц
блокировка таблицы при insert
    #33099868
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
pb 9.01, msSqlServer 2000
требутся, чтобы при запуске dw.update() новые строки добавлялись с "хинтом" (с блокировкой), то есть так:
Код: plaintext
insert into <table> with(tablockx) ...

возможно ли это где-то настроить? или придётся логику добаления в таблицу переносить на сервер БД? (всякие там view + триггер instead insert)?
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099887
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyвозможно ли это где-то настроить? или придётся логику добаления в таблицу переносить на сервер БД? (всякие там view + триггер instead insert)?
Обрабатывайте событие DataWindow sqlpreview.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099908
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Локшин Марк savosin_sergeyвозможно ли это где-то настроить? или придётся логику добаления в таблицу переносить на сервер БД? (всякие там view + триггер instead insert)?
Обрабатывайте событие DataWindow sqlpreview.
А по моему легче написать ХП и обновлять через них, чем возиться с SQLPreview.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099912
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
спасибо!
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099915
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 ASCRUS: то есть, dw.update() вообще не использовать?
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099926
Фотография Ikar
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergey2 ASCRUS: то есть, dw.update() вообще не использовать?
Т.е. использовать Stored Procedure Update, а не Update Properties (в окне Specify Update Properties сбросить флажок Allow Updates)
---
С уважением, IKAR

ikarhomecenter@narod.ru
IkarHomeCenter
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33099931
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergey2 ASCRUS: то есть, dw.update() вообще не использовать?
Это почему не использовать ??? Отключаете в DW UpdateProperties, включаете StoredProcedureUpdates. PB будет не сам скрипты генерить на обновление, а вызывать указанные ХП соотвествующе на добавление, обновление и удаление, в которых Вы и напишите свой Insert c блокировкой таблицы.

P.S. Я только никак не понимаю, зачем при вставке записи блокировать всю таблицу :)
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100053
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100183
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUS А по моему легче написать ХП и обновлять через них, чем возиться с SQLPreview.
Но если есть готовый проект, то гораздо быстрее будет подправить на SQLPreview, чем писать кучу хранимых процедур и править кучу DataWindow... Хотя зачем блокировать - действительно не понятно...
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100189
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergey2 ASCRUS: вот, http://www.sql.ru/forum/actualthread.aspx?tid=189052#1590905
Так не легче ли в триггере на получение максимального номера документа в SELECT через хинт ставить уровень SERIALIZABLE, чем блокировать всю таблицу ? Это "притормозит" до окончания Вашей транзакции все остальные DML операторы на таблицу. Вы же вообще режите любые операции над таблицей - то есть при таком хинте Ваша транзакция во первых будет ждать, пока все транзакции на таблице закончаться, во вторых во время выполнения будет не только "резать" вставляющих записи, но и вообще всех, даже читателей. Какой в этом глубокий спрашивается смысл ?

IMHO - не нужно кривизну проектирования БД решать посредством хинтов. Я не знаю логики Вашего приложения, но в случаях, если у Вас могут допускаться разрывы в номерах документов, то вообще легче поставить хинт в триггере на грязное чтения и никого не блокировать лишний раз. Так же можно увести логику с триггера в ХП, ответственной за добавление записей, в MSSQL лучше осторожничать с триггерами, это не ASA :)
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100281
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНо если есть готовый проект, то гораздо быстрее будет подправить на SQLPreview, чем писать кучу хранимых процедур и править кучу DataWindow... Хотя зачем блокировать - действительно не понятно...
Почитал по ссылке, оказывается не везде нужно делать... ну все равно я бы не так делал...
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100301
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUS
Так не легче ли в триггере на получение максимального номера документа в SELECT через хинт ставить уровень SERIALIZABLE, чем блокировать всю таблицу ?
да, я тоже так думаю.
---------
2 ASCRUS, Локшин Марк
меня волнует такая задача: таблица "документ" с тремя полями:
id int primary key

debit varchar(3)

dnum int

Код: plaintext
create table tdocument (id int identity, dnum int, debit varchar( 3 ))

Для некоторых дебетов (капитальные вложения = "106") надо в поле dnum ("номер позиции") присваивать последовательные номера (в разрезе всей таблицы). Для других значений поля debit такого тербования нет. Там может быть даже NULL .
--------------------

Как реализовать генерацию номера dnum ? да с учётом многопользовательского доступа к таблице "документ"? Я виду пока два способа.
1-й способ
в insert-триггере на таблице tdocument находить максимальный номер для дебетов "106" и заменять его в добавленных строках, соответственно увеличив. Проблема: возможны взаимные блокировки (deadlock) при добавлении строк в нескольких процессах. Для решения этого на соседнем форуме было предложено при insert блокировать таблицу ( insert into <table> with(TABLOCKX) ). Довольно мрачно, но deadlock'и пропали.

2-й способ
в insert-триггере на таблице tdocument обращаться к вспомогательной таблице-счёткику, у которой, в строке (например, с некоторым ключём) хранится последнее использованное значение счётчика. В триггере этот счётчик надо увеличить и присвоить добавленным строкам (у которых нужный дебет "106") новые значения. Проблема: при откате транзакции могут в таблице счётчиков оказаться "дыры" (если два пользователя взялись править таблицу счётчиков, у первого произошёл откат транзакции, но второй после этого всё-таки сохранил своё новое значение счётчика). Возможное решение: наложение блокировки на таблицу счётчиков! чтобы с ней мог работать одновременно только один триггер..

есть ли ещё способы, работающие реализации такого "выборочного" инкремента номера документа? поделитесь!
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100459
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я бы лично модифицировал второй способ. Не делал там инкрементное поле, а сделал таблицу только с одной записью и одним полем, в котором бы хранил последнее актуальное значение номера. Тогда бы схема работы выглядела так в ХП на добавление записи в tdocument:
1. Получаем новое значение счетчика, одновременно его увеличивая (UPDATE tdocument_num SET @Number = Number = Number + 1), таким образом вешаем экслюзивную блокировку на эту запись в таблице и сразу его получаем новое значение в переменную @Number.
2. Вставляем запись (INSERT INTO tdocument) уже сразу с присвоенным номером (в ней же можно для уверенности организовать UNIQUE, конечно если нет NULL полей, определяющих уникальность).

Клиент PB на добавление записи через Stored Proc Update вызывает эту ХП, передает значения полей в параметры, она отрабатывает. Далее как обычно COMMIT или ROLLBACK, в зависимости от того, что вернула DW.UPDATE().

Что теперь будет с другими сессиями ? Ничего страшного. Все будут работать как обычно, никаких deallock, кто одновременно пытается добавить записи будут ждать, пока update по commit освободит запись. Таким образом не будет разрывов, триггеров на MSSQL и никто не будет занимать лишнее места (зачем спрашивается с инкриментом или генераторами связываться, когда они изначально был сделан именно для того, чтобы не реагировать на транзакции).

P.S. Давно я на MSSQL ничего не делал, но наверное так бы и сделал, причем и на ASA тоже - мне кажется для блокировочников неплохое должно быть решение. Кстати если в таблицу еще ввести поле Имя, то таким образом можно в одной табличке хранить множество ведения собственных именованных счетчиков для разных нужд.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100491
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
спасибо!
ASCRUS2. Вставляем запись (INSERT INTO tdocument) уже сразу с присвоенным номером (в ней же можно для уверенности организовать UNIQUE, конечно если нет NULL полей, определяющих уникальность).
NULL'ы могут быть! да и поля с дебетом, отличным от "106" могут быть неуникальны..

Я тоже согласен, что подход со вспомогательной таблицей более работоспособен. Разве вместо вызода хранимой процедуры можно повесить триггер на update таблицы документа. И осталось разобраться с блокировкой таблицы со счётчиками, так как при откате транзакции возможны "дыры" в нумерации строк документа, см. .. Я имею ввиду, что (может быть) блокировать update, в котором изменяется значение счётчика мало, надо гарантировать работу триггера в одиночестве . То есть, пока он не завершится или не произойдёт откат транзакции, другой триггер не должен обращаться к таблице счётчиков (или к строке, соответствующей счётчику этого документа для дебета "106").
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33100517
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyРазве вместо вызода хранимой процедуры можно повесить триггер на update таблицы документа.
Я лично не рекомендую - Вы опять можете нарваться на deadlock-и и другие неприятные ситуации. Смысл в том, что в моем варианте Вы получаете и блокируете номер ДО начала операции вставки документа, а в AFTER триггере MSSQL номер будет получаться и блокироваться ПОСЛЕ вставки документа в таблицу.

savosin_sergeyИ осталось разобраться с блокировкой таблицы со счётчиками, так как при откате транзакции возможны "дыры" в нумерации строк документа, см. .. Я имею ввиду, что (может быть) блокировать update, в котором изменяется значение счётчика мало, надо гарантировать работу триггера в одиночестве . То есть, пока он не завершится или не произойдёт откат транзакции, другой триггер не должен обращаться к таблице счётчиков (или к строке, соответствующей счётчику этого документа для дебета "106").
Дыр не будет. В таблице tdocument_number нет инкремент полей - поле Number обычное int поле и обновляем мы его через UPDATE вручную, прибавляя для каждого нового документа единичку. Соотвествующе номер участвует в транзакции и если например она выполнится не успешно, то там так же будет откачен назад номер полученного документа, остальные же, кто пытается вставить запись, в это время по любому в "зависшем" состоянии ждут, пока с таблицы снимется блокировка. Соотвествующе если документ прошел по COMMIT, они получат новый номер, если не прошел по ROLLBACK, они получат тот же номер, который не смогла задействовать откатившая транзакцию сессия.

Так что мои 3 совета:
1. Откажитесь от триггера
2. Сделайте как я написал - создайте табличку с полем Number, добавьте в нее запись, напишите ХП и прицепите ее к PB
3. Почитайте поподробнее о транзакциях, блокировках и инкрементах в MSSQL, чтобы иметь более внятное представление обо всем этом.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33101523
sboyko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А если вопрос поставить по другому-
как штатными средствами ПБ заблокировать строку(без тригеров, без ХП, без хинтов) - чтобы работало для ПОЧТИ всех баз. Потом ее и разблокировать.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33101539
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Во всех DBMS, где есть транзакции, любой DML блокирует задействованные строки по записи до окончания транзакции, в которой он выполнен.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33101626
gz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
gz
Гость
Кину свои 5 копеек.
Если смотреть на Insert-ы, то "дырок" можно избежать, используя тот или иной механизм назначения номеров документов. Однако, если взглянуть в сторону Delete, а они неизбежны в реальных системах, то "дырки" появятся. Поэтому лучше честно сказать пользователю, что "дырки" будут и, исходя из этого предположения, выбирать механизм. И не стремиться к идеальному варианту без "дырок". Такой подход снимает много проблем.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33102539
sboyko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Anatoly Moskovsky
Я понимаю что транзакции блокируют, поэтому и хочу заблокировать строку РАНЬШЕ транзакции и делать с ней то, ЧТО НУЖНО МНЕ, а не соревноваться в скорости-кто изменит строку раньше.
В некоторых случаях-в частности - при поддержке псевдо Identity нужно заблокировать запись с идентити ДО выполнения операции. Потом ее разблокировать.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33103268
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
при поддержке псевдо Identity нужно заблокировать запись с идентити ДО выполнения операции. Потом ее разблокировать
Совершенно нет необходимости заранее что-либо блокировать:
В момент сохранения:
- получаем следующий ID (здесь блокируется генератор ID)
- вставляем в таблицу запись с ним
- commit (здесь все разблокируется)

До момента сохранения нет никаких транзакций.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33103414
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
как выяснилось, если в в одной транзакции к одной таблице выполняется сначала select, затем update, то велика вероятность взаимоблокировок (кроме msSqlserver'а я ничего нигде больше не проверял), вот ссылка , в ней пример номер 2..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33103488
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyкак выяснилось, если в в одной транзакции к одной таблице выполняется сначала select, затем update, то велика вероятность взаимоблокировок (кроме msSqlserver'а я ничего нигде больше не проверял), вот ссылка , в ней пример номер 2..

А зачем делать сначала Select?
- update idgen set curr_id = curr_id + 1 where tab_name = 'doc';
- select curr_id into :id from idgen where tab_name = 'doc';
- insert into doc (id, ...) values (:id, ...);
- commit

Первая из конкурирующих транзакций заблокирует запись с id до commit, остальные будут ожидать. После commit возникает снова конкуренция за блокировку среди оставшихся транзакций и все повторяется.

Это работает в любой DBMS.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33103503
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В этом случае правда возможен deadlock, если происходит вставка в 2 и более таблицы, и порядок получения ID таблиц в разных транзакциях отличается.

Например:

- (Транзакция1) update idgen set curr_id = curr_id + 1 where tab_name = 'doc';
- (Транзакция2) update idgen set curr_id = curr_id + 1 where tab_name = 'detail';
- (Транзакция1) update idgen set curr_id = curr_id + 1 where tab_name = 'detail';
здесь deadlock
- (Транзакция2) update idgen set curr_id = curr_id + 1 where tab_name = 'doc';

Поэтому все клиенты должны соблюдать единый порядок

- (Транзакция1) update idgen set curr_id = curr_id + 1 where tab_name = 'doc';
- (Транзакция2) update idgen set curr_id = curr_id + 1 where tab_name = 'doc';
здесь Транзакция2 ожидает commit 1
- (Транзакция1) update idgen set curr_id = curr_id + 1 where tab_name = 'detail';
- (Транзакция2) update idgen set curr_id = curr_id + 1 where tab_name = 'detail';
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104004
sboyko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Идеи конечно правильные - никто не возражает. Но кроме OLTP есть просто информационные системы, в которых блокировка документа является способом указать что с ним уже работают и другие изменения не приветствуются. Вопрос о конкурирующих транзакциях вообще не стоит. Можно поставить TimeStamp, но можно просто блокировать. DeadLock не будет потому работа идет с одной таблицей.
Поэтому вопрос и был, что все таки в PowerBuilder позволяет делать явные операции блокировок-получается ничего.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104711
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
эти блокировки много от чего зависят, вряд ли можно обойтись какими-то настройками, вроде autocommit=yes/no..
в msSqlServer2k, например, на них влияет
настройка isolation level транзакции,

"хинты" в операторах insert, update, select, delete

ну и, конечно же, от выбора СУБД тоже многое зависит! так что либо использовать хранимые процедуры, либо писать нормальные триггеры, т.е. управлять транзакциями на СУБД, а не из powerBuilder'а..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104907
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyэти блокировки много от чего зависят, вряд ли можно обойтись какими-то настройками, вроде autocommit=yes/no..
в msSqlServer2k, например, на них влияет
настройка isolation level транзакции,

"хинты" в операторах insert, update, select, delete

ну и, конечно же, от выбора СУБД тоже многое зависит! так что либо использовать хранимые процедуры, либо писать нормальные триггеры, т.е. управлять транзакциями на СУБД, а не из powerBuilder'а..


Вернемся к теме.
Приведите ситуацию, в которой по Вашему мнению нужна явная блокировка:
Код: plaintext
insert into <table> with(tablockx) ...
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104967
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sboykoИдеи конечно правильные - никто не возражает. Но кроме OLTP есть просто информационные системы, в которых блокировка документа является способом указать что с ним уже работают и другие изменения не приветствуются. Вопрос о конкурирующих транзакциях вообще не стоит. Можно поставить TimeStamp, но можно просто блокировать. DeadLock не будет потому работа идет с одной таблицей.
Поэтому вопрос и был, что все таки в PowerBuilder позволяет делать явные операции блокировок-получается ничего.
вопрос стоял (хоть и в скрытой форме) так "как мне реализовать счётчик записей, удовлетворяющих некоторому условию". Просто я его уже задал на другом форуме, а здесь начал "издалека".

2 всем:
Интересно сравнить ответы чистых "серверников" в разделе mssqlserver и "прикладников" в разделе powerBuilder..

ответ ASCRUS (а затем и других) с блокировкой вспомогательной таблицы посредством update table очень помог (хотя и было непонятно сначала, что блокировка update не снимается до commit tran )! только не понятно, чем триггер плох? та же хранимая процедура, хоть и сработает после добавления, но номер проставить всё же можно..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104979
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky
Вернемся к теме.
Приведите ситуацию, в которой по Вашему мнению нужна явная блокировка:
Код: plaintext
insert into <table> with(tablockx) ...

Эта тема была создан всвязи с таким insert 'ом. Но сейчас я думаю, что "хинт" на insert вешать -- не дело. Намного элегантнее всё решить в триггере, блокируя вспомогательную таблицу. Хотя в указанном примере вспомогательная таблица вообще не используется..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33104987
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а сама проблема звучит так
авторпроблема: в таблице есть поля "первичный ключ", "дебет" и "номер позиции". для некоторых дебетов (капитальные вложения, 106) надо в поле "номер позиции" присваивать последовательные номера (в разрезе всей таблицы)
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105257
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyа сама проблема звучит так
авторпроблема: в таблице есть поля "первичный ключ", "дебет" и "номер позиции". для некоторых дебетов (капитальные вложения, 106) надо в поле "номер позиции" присваивать последовательные номера (в разрезе всей таблицы)

server side
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
table doc ( id identity, debit, pos);
table idgen (name, curr_id);
trigger on doc after insert or update of debit
  if new.debit =  106  then
     update idgen set curr_id = curr_id +  1  where name = 'doc.pos';
     select curr_id into :new.pos from idgen where name = 'doc.pos';
  end if;
end trigger;

client side
Код: plaintext
1.
2.
3.
4.
TR1> insert into doc (debit) values ( 106 );
TR2> insert into doc (debit) values ( 106 ); -- TR2 ждет commit в TR1 
TR1> commit 
TR2> commit 

Это работает в любой DBMS без всяких явных блокировок и прочего.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105318
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergeyИнтересно сравнить ответы чистых "серверников" в разделе mssqlserver и "прикладников" в разделе powerBuilder..

ответ ASCRUS (а затем и других) с блокировкой вспомогательной таблицы посредством update table очень помог
И к какому классу Вы относите ASCRUS'а?
Кстати, я хотел предложить похожий вариант...
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105435
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Anatoly Moskovsky
авторtable doc ( id identity, debit, pos);
table idgen (name, curr_id);
trigger on doc after insert or update of debit
if new.debit = 106 then
update idgen set curr_id = curr_id + 1 where name = 'doc.pos';
select curr_id into :new.pos from idgen where name = 'doc.pos';
end if;
end trigger;

да, блокировки все сами правильно расставляются первым update'ом, я теперь тоже вкурсе! хотя ваш скрипт немного бы изменил (с учётом того, что в mss в триггере обрабатываются сразу все изменённые/добавленные записи, а не одна.. да и документ надо изменить): (синтаксис ms sql 2000, с теми же таблицами)
Код: 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.
33.
--сплагиачено у М.(bumsy)
create table doc ( id int identity, debit varchar( 3 ), pos int)
create table idgen (name varchar( 20 ), curr_id int)
create index ix_doc_name ON idgen (name)

CREATE TRIGGER [TR_DOCS_I] ON dbo.doc
FOR INSERT
AS
BEGIN
 DECLARE @c_num int -- значение из таблицы счетчиков
 DECLARE @rc int -- кол-во обрабатываемых в триггере строк
	
 SELECT @rc = COUNT(*)
 FROM inserted
 WHERE inserted.debit = '106'

 IF @rc >  0  
 BEGIN -- генерация номера по порядку

  UPDATE idgen
  SET @c_num = curr_id = curr_id + @rc
  WHERE name = 'doc.pos'
  --теперь другой аналогичный триггер будет ждать конца транзакции

  SET @c_num = @c_num - @rc

  UPDATE doc
  SET @c_num =  pos =  @c_num +  1 
  FROM doc, inserted
  WHERE doc.id = inserted.id AND doc.debit = '160'

 END
END
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105447
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Локшин Марк savosin_sergeyИнтересно сравнить ответы чистых "серверников" в разделе mssqlserver и "прикладников" в разделе powerBuilder..

ответ ASCRUS (а затем и других) с блокировкой вспомогательной таблицы посредством update table очень помог
И к какому классу Вы относите ASCRUS'а?
Кстати, я хотел предложить похожий вариант...
это форум можно назвать "прикладным". Прикладывается он к powerbuilder'у ;-). А на msSqlServer-форуме обитают "теоретики" (ничего против не имею!). И решения одной и той же проблемы различаются..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105490
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
savosin_sergey
Ну во первых вместо:
Код: plaintext
1.
2.
3.
4.
 SELECT @rc = COUNT(*)
 FROM inserted
 WHERE inserted.debit = '106'

 IF @rc >  0  
лучше бы привыкать писать:
Код: plaintext
1.
2.
3.
4.
 IF EXISTS( 
   SELECT *
   FROM inserted
   WHERE inserted.debit = '106')
отличия - Ваш вариант будет сканом перебирать всю таблицу, мой при встрече первого подходящего условия сразу же закончит работу. Вариант с COUNT(*) бывает полезно применять в других случаях - когда нужно заблокировать по фильтру все записи через SELECT/хинт не возвращая результат.

Далее - Вы не вняли моему совету сделать все на ХП и все таки влепили в триггер, так что могу смело критиковать:
В моем варианте номер получается до операции с таблицей Doc, таким образом мы получаем и блокируем/резервируем свой новый номер для сессии, потом просто вставляем его сразу с записью. В Вашем варианте Вы вставляете запись, потом получаете номер, потом обновляете ту же запись. Это плохой вариант - затягиваем транзакцию, увеличиваем лог, неявно вызываем UPDATE триггера не по делу, не можем на таблицу повесить CHECK ((debit <> '160' and pos is null) or (debit = '160' and pos is not null)). В общем я еще раз настоятельно рекомендую подумать о ХП исключительно из за того, что в качестве РСУБД выступает MSSQL. Была бы та же ASA, где можно прямо в BEFORE TRIGGER инициализировать значение вставляемого/изменяемого поля, я бы там сразу же порекомендовал триггер.

авторИ к какому классу Вы относите ASCRUS'а?
Ну на данном форуме я исключительно прикладник, на Sybase я исключительно серверник, а к MSSQL слава богу вот уже 2 года никакого отношения не имею :)
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105835
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUS savosin_sergey
Ну во первых вместо:
Код: plaintext
1.
2.
3.
4.
 SELECT @rc = COUNT(*)
 FROM inserted
 WHERE inserted.debit = '106'

 IF @rc >  0  
лучше бы привыкать писать:
Код: plaintext
1.
2.
3.
4.
 IF EXISTS( 
   SELECT *
   FROM inserted
   WHERE inserted.debit = '106')


переменная @rc дальше используется в триггере.

ASCRUSВ общем я еще раз настоятельно рекомендую подумать о ХП исключительно из за того, что в качестве РСУБД выступает MSSQL. Была бы та же ASA, где можно прямо в BEFORE TRIGGER инициализировать значение вставляемого/изменяемого поля, я бы там сразу же порекомендовал триггер. Подумаю. Правда в msSql2000 появились instead-триггеры ("вместо"), но все примеры использования я видел только для вьюх.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33105870
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я сам не пользовался instead-of триггерами, но читал по форуму MSSQL, что при их использовании возникают различные проблемы. Так что лучше перед их использованием порыться по форуму "на всякий пожарный".
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33106401
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНу на данном форуме я исключительно прикладник, на Sybase я исключительно серверник, а к MSSQL слава богу вот уже 2 года никакого отношения не имею :)
Ну что касается обсуждаемого вопроса, то насколько я понимаю, ASE будет себя вести аналогично MS SQL...
Это же пельмени, но они же равиоли...
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33106488
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Локшин Марк авторНу на данном форуме я исключительно прикладник, на Sybase я исключительно серверник, а к MSSQL слава богу вот уже 2 года никакого отношения не имею :)
Ну что касается обсуждаемого вопроса, то насколько я понимаю, ASE будет себя вести аналогично MS SQL...
Это же пельмени, но они же равиоли...
Что то мне кажется, что на ASE эта задача будет еще сложнее решаться - вряд ли там есть instead триггера или же хинты на DML операторы.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33106699
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUSЧто то мне кажется, что на ASE эта задача будет еще сложнее решаться - вряд ли там есть instead триггера или же хинты на DML операторы.
Так есть же вариант с sp?
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33106716
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
и без instead-триггера можно:
ASCRUSтак что могу смело критиковать:
В моем варианте номер получается до операции с таблицей Doc, таким образом мы получаем и блокируем/резервируем свой новый номер для сессии, потом просто вставляем его сразу с записью. В Вашем варианте Вы вставляете запись, потом получаете номер, потом обновляете ту же запись. Это плохой вариант - затягиваем транзакцию, увеличиваем лог, неявно вызываем UPDATE триггера не по делу, не можем на таблицу повесить CHECK ((debit <> '160' and pos is null) or (debit = '160' and pos is not null)). В общем я еще раз настоятельно рекомендую подумать о ХП исключительно из за того, что в качестве РСУБД выступает MSSQL. Была бы та же ASA, где можно прямо в BEFORE TRIGGER инициализировать значение вставляемого/изменяемого поля, я бы там сразу же порекомендовал триггер.

проверку можно в after-триггер вставить, так как он выполняется в одной транзакции вместе с вызвавшем его insert 'ом. То есть rollback откатит и вставку записей:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
drop table tdoc
go
create table tdoc (id int identity, dnum int, debit varchar( 3 ))
go
create trigger tdoc_ins on tdoc for insert
as begin
 if exists(select * from inserted where debit='106') begin
  raiserror('нельзя вводить дебет 106!',  16 ,  1 )
  rollback
 end
end
go

insert into tdoc(dnum, debit)
select  1 , '101'
union all
select  2 , '102'
union all
select  3 , '106'

select * from tdoc
(пустой результат)

а то, что триггер вызывается после вставки, а не вместо -- ничего не испортит в алгоритме расстановки нумерации. Откатится как счётчик, так и строка в документе, даже если между insert и триггером вклинится другой триггер..
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33106809
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ASCRUSЭто плохой вариант - затягиваем транзакцию, увеличиваем лог, неявно вызываем UPDATE триггера не по делу
по поводу увеличения лога:
рассмотрим таблицы (документ, счётчик) и триггер на документ:
Код: 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.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
drop table idgen
go
create table idgen (name varchar( 20 ), curr_id int)
go
create index ix_doc_name ON idgen (name)
go
insert into idgen (name, curr_id) values ('doc.pos',  1 )
go
drop table doc
go
create table doc ( id int identity, debit varchar( 3 ), pos int)
go

CREATE TRIGGER [TR_DOCS_I] ON dbo.doc
FOR INSERT
AS
BEGIN
 DECLARE @c_num int -- значение из таблицы счетчиков
 DECLARE @rc int -- кол-во обрабатываемых в триггере строк
	
 if exists(select * from inserted where debit='105') begin
  raiserror('нельзя добавлять документ с дебетом "105"',  16 ,  1 )
  rollback
 end

 SELECT @rc = COUNT(*)
 FROM inserted
 WHERE inserted.debit = '106'

 IF @rc >  0  
 BEGIN -- генерация номера по порядку

  UPDATE idgen
  SET @c_num = curr_id = curr_id + @rc
  WHERE name = 'doc.pos'
  --теперь другой аналогичный триггер будет ждать конца транзакции

  SET @c_num = @c_num - @rc

  UPDATE doc
  SET @c_num =  pos =  @c_num +  1 
  FROM doc, inserted
  WHERE doc.id = inserted.id AND doc.debit = '106'

 END
END

сделаем две вставки: вызывающую откат и без отката: (триггер вызывается один раз на каждый insert into doc.. )
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
insert into doc (debit)
select '106'
union all
select '103'
union all
select '105'
go
select * from doc
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
insert into doc (debit)
select '106'
union all
select '103'
union all
select '106'
go
select * from doc
да, лог увеличивается за счёт update , сказать нечего.. на то он и триггер. вот лог этих операций вставки:
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33107946
Vidok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
savosin_sergey
Как реализовать генерацию номера dnum ? да с учётом многопользовательского доступа к таблице "документ"? Я виду пока два способа.
1-й способ
..... было предложено при insert блокировать таблицу ( insert into <table> with(TABLOCKX) ). Довольно мрачно, но deadlock'и пропали.

2-й способ
... Возможное решение: наложение блокировки на таблицу счётчиков! чтобы с ней мог работать одновременно только один триггер..

есть ли ещё способы, работающие реализации такого "выборочного" инкремента номера документа? поделитесь!

Да есть, без триггеров и явных (ручных) блокировок, на уровне RC:

insert into <table> (id, debit, num)
values (:id, :debit, GetNextNumOnDebit(debit, 1));

insert into <table> (id, debit, num)
values (:id, :debit, GetNextNumOnDebit(debit, 2));
.
.
.
insert into <table> (id, debit, num)
values (:id, :debit, GetNextNumOnDebit(debit, 100));

commit;
// rollback;


/* function double GetNextNumOnDebit(string debit, double num) RPCFUNC ALIAS FOR "~"xxxx~".~"GetNextNumOnDebit~"" */

GetNextNumOnDebit должна быть спроектирова так, чтобы
после первого вызова до COMMIT / ROLLBACK, получение значений другими сессиями для этого значения debit, было невозможно. Самый прямолинейный способ - использование вспомогательной таблицы и метода UPDATE ... SET NUM = NUM+NUM_INTERVAL WHERE... с последующим SELECT NUM INTO ...
Механизм, тут уже объяснили.

При отсутствии желания все делать правильно и красиво, можно и хранимую процедуру заменить на метод объекта или глобальную функцию и все писать на PB (я так не делаю) );.
...
Рейтинг: 0 / 0
блокировка таблицы при insert
    #33108676
Фотография savosin_sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
понятно. очень похоже на триггер, который использует дополнительную таблицу и блокирует строку в ней до подтверждения или отката транзакции
...
Рейтинг: 0 / 0
43 сообщений из 43, показаны все 2 страниц
Форумы / PowerBuilder [игнор отключен] [закрыт для гостей] / блокировка таблицы при insert
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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