Поиск:

Ответ в темуСоздание новой темы Создание опроса
> блокировка записи в таблицу MS SQL, MSSQL Server 2000, SDAC 
:(
    Опции темы
Гость_BasilL
Дата 22.6.2005, 20:12 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Требуется на некоторое время запретить запись в таблицу 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 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



SET TRAN ISOLATION LEVEL SERIALIZABLE


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
BasilL
Дата 23.6.2005, 19:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 26.5.2005
Где: Челябинск обл.

Репутация: нет
Всего: 1



To Vit
Цитата(Vit @ 22.6.2005, 23:31)
SET TRAN ISOLATION LEVEL SERIALIZABLE


Так не прокатит. Нелься создавать дополнительную транзакцию - в это время проходит другая транзакция, а пока она не завершена, новую я стартовать не могу, а применить "SET TRAN ISOLATION LEVEL SERIALIZABLE" к запущенной на шаге 2) транзакции тоже нельзя - это ничего не даст - таблица, запись в которую надо блокировать в ней не задействована. К тому же транзакция на шаге 2) не использует ХП, а прописать "SET TRAN ISOLATION LEVEL SERIALIZABLE" в компоненты MSTable и MSQuery от SDAC вроде-бы некуда.

Вот кусок кода, когда отрабатывает транз. на шаге 2):



Код

    try
        ConnectionData.ConnectionDataModule.ServerConnection.StartTransaction;

        if (VirtualTable1.State = dsInsert) or (VirtualTable1.State = dsEdit) then
                VirtualTable1.Post;
        if (VirtualTable2.State = dsInsert) or (VirtualTable2.State = dsEdit) then
                VirtualTable2.Post;

        VirtualTable1.First;

        if Check_mpz_kol() then
                begin
                if ConnectionData.ConnectionDataModule.ServerConnection.InTransaction then
                ConnectionData.ConnectionDataModule.ServerConnection.Rollback;
                Status.Caption := 'Документ не проведен.';
                exit;
                end;
        
        MsTable1.Append;

        MsTable1.FieldValues['RecID'] := RecID;
        MsTable1.FieldValues['НомерДокумента'] := 
              VirtualTable1.FieldValues['НомерДокумента'];

       ...

        btnPrint.Enabled := true;

        ConnectionData.ConnectionDataModule.ServerConnection.Commit;
        Status.Caption := 'Документ проведен.';

        exept
        ...
        end;
       



т.е. в это время производится запись из нескольких виртуальных таблиц в таблицы на сервере.
И надо быть уверенным, что таблица с датой в это время не изменялась.
PM MAIL   Вверх
Vit
Дата 23.6.2005, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Хм... тогда только hint на запросах ставить... больше по-моему никак... И вообще такие действия должны ИМХО быть в пределах одной транзакции...

Цитата
В BDE был предусмотрен монопольный доступ и Table.Lock. Нет ли чего-нибудь похожего в связке SDAC - MS SQL?


Открыть таблицу запросом:

Код

Select * From Table with (tablockx)





--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
BasilL
Дата 23.6.2005, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 26.5.2005
Где: Челябинск обл.

Репутация: нет
Всего: 1



To Vit
Цитата(Vit @ 23.6.2005, 19:47)
тогда только hint на запросах ставить


Так вот, нету у меня в этой транзакции запросов, не нужны они.
Если только специально для хинт-а какой-нибудь в начале транзакции запускать... типа Select * from <таблица_с_датой> with (tablockx). А? Как-то не очень расиво получается.

Тут в одной статейке только что прочитал, что есть такая хп - sp_getapplock ("...Смысл ее в следующем – блокировка произвольного ресурса...").
Нельзя ли это как-то применить?

Это сообщение отредактировал(а) BasilL - 23.6.2005, 20:15
PM MAIL   Вверх
Vit
Дата 23.6.2005, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Цитата(BasilL @ 23.6.2005, 11:01)
Так вот, нету у меня в этой транзакции запросов, не нужны они.



Не бывает транзакций без запросов... в отношении SQL Server... Он просто не позволит делать ничего кроме запросов. Даже если ты открываешь таблицу каким-то компонентом типа Table в отличие от парадокса реально выполняется запрос типа Select * From Table, поэтому замени свои компоненты Table на запросы и используй блокировки.


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
BasilL
Дата 23.6.2005, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 26.5.2005
Где: Челябинск обл.

Репутация: нет
Всего: 1



Я понимаю, что по-сути, нет транзакции без запросов, но дело не в этом.
Нельзя заменить Table на Query, я не смогу написать SQL.Text типа "insert into ... from... , поскольку from-то как раз и нету. В транзакции я переписываю некий набор записей из компонента TVirtualTable в TTable. TVirtualTable - это виртуальная таблица из набора SDAC (поэтому его и выбрал), на сервере этих данных нет и быть не может, они появятся там только после Table.post.
Вот и выходит, что нельзя все это описать запросом.

p.s. Insert ... values тоже не подойдет.
PM MAIL   Вверх
Vit
Дата 23.6.2005, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Ничего не понял... Извини я не знаком с этим пакетом... Не понимаю что за виртуальные таблицы... Для их осуществления можно использовать View, temp таблицы и т.п. И любой компонент Table абсолютно эквивалентен live запросу Select * From Table
Добавлено @ 21:35
Кажись понял... Это решаемо при помощи запросов, псевдокод такой:

Код

query.sql.text:='Select top 1 * From Table with (tablockx)'; //это таблица в которую будешь писать
query.open;
while not VirtualTable.eof do
  begin
    query.append; //записываем в Select запрос как в таблицу
    query.fieldbyname('чего-то там').value := VirtualTable..fieldbyname('чего-то там').value; 
    query.fieldbyname('чего-то там2').value := VirtualTable..fieldbyname('чего-то там2').value; 
    query.fieldbyname('чего-то там3').value := VirtualTable..fieldbyname('чего-то там3').value; 
    query.fieldbyname('чего-то там4').assign(VirtualTable..fieldbyname('чего-то там4')); 
    query.post;
    VirtualTable.next;
  end;



--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
BasilL
Дата 24.6.2005, 12:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 26.5.2005
Где: Челябинск обл.

Репутация: нет
Всего: 1



2Vit

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

Объясню смысл: так, как ты написал (или как у меня сейчас, похоже) в таблицу я добавляю запись (записи). Перед этим запускается функция (if Check_mpz_kol() then ... - см. код), в которой сначала в таблицу <CurrentDate> пишется определенная дата, затем делается запрос к серверу, который возвращает определенный набор данных (они зависят от даты), эти данные проверяются, и если они удовлетворяют определенным условиям, функция возвращает true, и выполнение транзакции продолжается (тут и начинается перенос данных из виртуальной таблицы, который ты описал), если нет - откат. Так вот, таблицу с датой и надо залочить на время выполнения функцией проверки, точнее даже достаточно на время получения данных, которые проверяем - чтобы быть уверенными, что эти данные соответсвуют установленной дате. После проверки таблицу желательно разблокировать, чтобы не держать других клиентов - проверка идет быстро, а вот до конца транзакции еще долго.
А если я в начало основной транзакции (где переносятся записи из вирт. табл.) добавлю выполнение запроса типа "select * from CurrentDate with (tablelockx)", то, конечно, нужного результата добьюсь, но буду долго держать таблицу блокированной - это нежелательно.
А вставить такой запрос в процедуру проверки не получиться - сервер не даст запустить вторую транзакцию, в это время уже есть активная транзакция; на всякий случай пробовал - сервак, ессно, ругается: user transaction already in progress.

з.ы. логика формирования проверяемых данных организована на сервере, перенести ее на клиента нельзя, поэтому сделать что-то вроде TQuery с параметром, в который и ложить дату не выйдет.

Странная, наверное, у меня ситуация. А что делать?
PM MAIL   Вверх
Vit
Дата 24.6.2005, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Мдя... даже не знаю... Может над архитектурой подумать?


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
BasilL
Дата 25.6.2005, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 84
Регистрация: 26.5.2005
Где: Челябинск обл.

Репутация: нет
Всего: 1



Вот и я не знаю.
А может быть лучше создать некий пользовательский ресурс и блокировать его sp_getapplock?

Это сообщение отредактировал(а) BasilL - 25.6.2005, 12:33
PM MAIL   Вверх
Vit
Дата 26.6.2005, 03:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Похоже на то


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Базы данных и репортинг"
Vit
Петрович

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами


Обязательно указание:

1. Базы данных (Paradox, Oracle и т.п.)

2. Способа доступа (ADO, BDE и т.д.)


  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • Вопросы по SQL и вопросы по базам данных не связанные с Дельфи задавать здесь

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Vit, Петрович.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Базы данных и репортинг | Следующая тема »


 




[ Время генерации скрипта: 0.0764 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.