| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Базы данных и репортинг > блокировка записи в таблицу MS SQL |
| Автор: Гость_BasilL 22.6.2005, 20:12 |
| Требуется на некоторое время запретить запись в таблицу MS SQL. При этом чтение разрешается. Доступ через SDAC v3. Подробнее: есть некая таблица "CurrentDate". В ней хранится рабочая дата. На рабочих местах клиентов в глобальной переменной хранится "своя" дата - у разных клиентов она может быть разной. При определенных условиях у конкретного клиента возникает необходимость в таких действиях: 1) сначала записать в таблицу на серваке "свою" дату (так, чтобы транзакция завершилась и сервер принял запись и увидел изменение) 2) после этого начинается новая транзакция (где и производится все, что клиенту надо), по окончании этой транзакции, дата в таблице на сервере снова возвращается та, которая была. Проблема возникает в том случае (теоретически), когда между шагами 1) и 2) другой клиент меняет дату в таблице на сервере, то шаг 2) у первого клиента отрабатывается неправильно. Вот и надо на какое-то время (как-правило, секунды) запретить всем запись в таблицу с датой. p.s. Объединять транзакции и вставлять что-то вроде "UPDLOCK" не подходит. В BDE был предусмотрен монопольный доступ и Table.Lock. Нет ли чего-нибудь похожего в связке SDAC - MS SQL? Вроде бы, более-менее понятно описал суть проблемы. Заранее, спасибо. |
| Автор: Vit 22.6.2005, 23:31 |
| SET TRAN ISOLATION LEVEL SERIALIZABLE |
| Автор: BasilL 23.6.2005, 19:18 | ||||
To Vit
Так не прокатит. Нелься создавать дополнительную транзакцию - в это время проходит другая транзакция, а пока она не завершена, новую я стартовать не могу, а применить "SET TRAN ISOLATION LEVEL SERIALIZABLE" к запущенной на шаге 2) транзакции тоже нельзя - это ничего не даст - таблица, запись в которую надо блокировать в ней не задействована. К тому же транзакция на шаге 2) не использует ХП, а прописать "SET TRAN ISOLATION LEVEL SERIALIZABLE" в компоненты MSTable и MSQuery от SDAC вроде-бы некуда. Вот кусок кода, когда отрабатывает транз. на шаге 2):
т.е. в это время производится запись из нескольких виртуальных таблиц в таблицы на сервере. И надо быть уверенным, что таблица с датой в это время не изменялась. |
| Автор: Vit 23.6.2005, 19:47 | ||||
Хм... тогда только hint на запросах ставить... больше по-моему никак... И вообще такие действия должны ИМХО быть в пределах одной транзакции...
Открыть таблицу запросом:
|
| Автор: BasilL 23.6.2005, 20:01 | ||
To Vit
Так вот, нету у меня в этой транзакции запросов, не нужны они. Если только специально для хинт-а какой-нибудь в начале транзакции запускать... типа Select * from <таблица_с_датой> with (tablockx). А? Как-то не очень расиво получается. Тут в одной статейке только что прочитал, что есть такая хп - sp_getapplock ("...Смысл ее в следующем – блокировка произвольного ресурса..."). Нельзя ли это как-то применить? |
| Автор: Vit 23.6.2005, 20:21 | ||
Не бывает транзакций без запросов... в отношении SQL Server... Он просто не позволит делать ничего кроме запросов. Даже если ты открываешь таблицу каким-то компонентом типа Table в отличие от парадокса реально выполняется запрос типа Select * From Table, поэтому замени свои компоненты Table на запросы и используй блокировки. |
| Автор: BasilL 23.6.2005, 20:44 |
| Я понимаю, что по-сути, нет транзакции без запросов, но дело не в этом. Нельзя заменить Table на Query, я не смогу написать SQL.Text типа "insert into ... from... , поскольку from-то как раз и нету. В транзакции я переписываю некий набор записей из компонента TVirtualTable в TTable. TVirtualTable - это виртуальная таблица из набора SDAC (поэтому его и выбрал), на сервере этих данных нет и быть не может, они появятся там только после Table.post. Вот и выходит, что нельзя все это описать запросом. p.s. Insert ... values тоже не подойдет. |
| Автор: Vit 23.6.2005, 21:30 | ||
| Ничего не понял... Извини я не знаком с этим пакетом... Не понимаю что за виртуальные таблицы... Для их осуществления можно использовать View, temp таблицы и т.п. И любой компонент Table абсолютно эквивалентен live запросу Select * From Table Добавлено @ 21:35 Кажись понял... Это решаемо при помощи запросов, псевдокод такой:
|
| Автор: BasilL 24.6.2005, 12:36 |
| 2Vit Согласен с тобой, так работать будет. Вот только лочить надо не ту таблицу в которую добавляю запись, а совсем другую. (таблица, которую надо блокировать, и таблица в которую пишу - это совершенно разные, не связанные между собой таблицы). Объясню смысл: так, как ты написал (или как у меня сейчас, похоже) в таблицу я добавляю запись (записи). Перед этим запускается функция (if Check_mpz_kol() then ... - см. код), в которой сначала в таблицу <CurrentDate> пишется определенная дата, затем делается запрос к серверу, который возвращает определенный набор данных (они зависят от даты), эти данные проверяются, и если они удовлетворяют определенным условиям, функция возвращает true, и выполнение транзакции продолжается (тут и начинается перенос данных из виртуальной таблицы, который ты описал), если нет - откат. Так вот, таблицу с датой и надо залочить на время выполнения функцией проверки, точнее даже достаточно на время получения данных, которые проверяем - чтобы быть уверенными, что эти данные соответсвуют установленной дате. После проверки таблицу желательно разблокировать, чтобы не держать других клиентов - проверка идет быстро, а вот до конца транзакции еще долго. А если я в начало основной транзакции (где переносятся записи из вирт. табл.) добавлю выполнение запроса типа "select * from CurrentDate with (tablelockx)", то, конечно, нужного результата добьюсь, но буду долго держать таблицу блокированной - это нежелательно. А вставить такой запрос в процедуру проверки не получиться - сервер не даст запустить вторую транзакцию, в это время уже есть активная транзакция; на всякий случай пробовал - сервак, ессно, ругается: user transaction already in progress. з.ы. логика формирования проверяемых данных организована на сервере, перенести ее на клиента нельзя, поэтому сделать что-то вроде TQuery с параметром, в который и ложить дату не выйдет. Странная, наверное, у меня ситуация. А что делать? |
| Автор: Vit 24.6.2005, 15:13 |
| Мдя... даже не знаю... Может над архитектурой подумать? |
| Автор: BasilL 25.6.2005, 12:33 |
| Вот и я не знаю. А может быть лучше создать некий пользовательский ресурс и блокировать его sp_getapplock? |
| Автор: Vit 26.6.2005, 03:45 |
| Похоже на то |