powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Захват единственной записи
6 сообщений из 6, страница 1 из 1
Захват единственной записи
    #32027855
Варяг
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Рискну перебросить еще вопросик:
Задача следующая: Надо для некоторой экранной формы(не грид) обеспечить доступ
к единственной строке таблицы так, чтобы массив сканировался другими задачами
без задержек, но другой юзер не смог бы скорректировать эту запись ( аналог
RLock() в языках xBase ).
Делаю так:
declare c1 cursor SCROLL DYNAMIC for
select aserty,z,m from a1 with(HOLDLOCK)
for update
open c1
declare @aserty int,@z char(10),@m numeric(18,0)
-- Позиционирование в таблице, например так
fetch next from c1 into @aserty,@z,@m
while @aserty<>'680580'
fetch next from c1 into @aserty,@z,@m
-- Вышли на нужную запись

--Далее отдаем в экранную форму и юзер минут 5 соображает что и как корректировать.При
этом таблица сканируется и соседние записи корректируются но текущую запись
через простой UPDATE не изменить, то есть вроде запись захвачена.
Затем
UPDATE a1 set z='proc1 ',m=66 WHERE CURRENT OF c1

Все хорошо, если в этот момент другой юзер таким же курсором не изменит эту
же запись (за 2 минуты )
Тогда - облом, либо перечитай запись и сразу корректируй - это пройдет. Как
же все-таки изобразить RLock() ?
Можно ли определить, что эта запись уже кем-то прихвачена?
...
Рейтинг: 0 / 0
Захват единственной записи
    #32027894
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Возможно, Glory меня поправит, но тут я вижу 2 способа решения:

1. Введение поля типа TimeStamp и при сбросе своих измененных данных включать это поле в условие Where (аналог оптимистической буферизации). Т.е. если другой пользователь изменил запись пока ты ее редактировал, то неизбежно было изменено поле TimeStamp и после команды UPDATE ты получишь @@RowCount=0. Дальше делаешь выводы: писать поверх чужих изменений или обновить.

2. Этот вариант значительно хуже. Надо обернуть твою команду транзакцией. Чтобы не блокировалась вся страница, необходимо создать специальное служебное поле (тип и содержание значения не имеют). Код примерно следующий:

BEGIN TRANSACTION OneColumnOneRecord
UPDATE MyTable SET EditColumn=EditColumn WHERE RecordID=<код редактируемой записи>

Далее берешь запись на редактирование
SELECT * FROM MyTable WHERE RecordID=<код редактируемой записи>

И после завершения редактирования снимаешь транзакцию, причем ROLLBACK или COMMIT совершенно не важно
ROLLBACK TRANSACTION OneColumnOneRecord

Этот способ плох именно наличием открытой транзакции в течении неопределенно долгого времени. Правда заблокировано только одно поле одной строки, но все-равно, подозреваю, что придется выставлять всем "грязный" уровень изоляции (READ UNCOMMITED), чтобы вообще можно было делать выборки пока кто-то редактирует одну запись. Что уже не есть хорошо.
...
Рейтинг: 0 / 0
Захват единственной записи
    #32027961
Варяг
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2ВладимирМ
П1. ИМХО не в тему! Я говорил о скроллируемом динамическом курсоре. При этом @@RowCount бессмысленен, Where некуда вставлять, TimeStamp (если есть) отслеживается сервером автоматом, либо через контрольные суммы.

По п2. "Правда заблокировано только одно поле одной строки" - а что, уже есть FIELDLOCK ? Я-то думал что только от TABLOCK & PAGELOCK добрались до ROWLOCK

Я хотел именно уйти от предлагаемой Вами схемы и в качестве решения наиболее близок мне курсор. В моем примере именно соблюдается выполнение ВСЕХ селектов при текущих (мб и неизвестных) установках уровня изоляции, и всех апдейтов, не затрагивающих данную запись. Так что курсор мне ПОЧТИ подходит. Однако различные клиенты (или коннекты) с таким курсором конкурируют за эту запись совершенно одинаково, вне зависимости от того, кто первым к ней обратился.
Я хотел бы чтобы захват надежно удерживал запись, вне зависимости от типов других курсоров в иных приложениях, средств разработки и способах доступа к серверу (Fox/Delpi, ADO/ODBC...)
Вопрос остается - как определить,что нужная запись уже кем-то прихвачена и как не дать другому ее изменять?
...
Рейтинг: 0 / 0
Захват единственной записи
    #32027982
Miha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну уж если совсем в лоб, то:

-- выбираем информацию для редактирования
-- (по aserty нужен уникальный индекс)
BEGIN TRAN
select aserty,z,m from a1 with(UPDLOCK,ROWLOCK,HOLDLOCK) where aserty='680580'


-- собственно изменяем и сразу завершаем транзакцию
UPDATE a1 set z='proc1 ',m=66 where aserty='680580'
COMMIT

Минус - плохой UPDLOCK будет висеть все время пока открыта транзакция. Однако, он хоть не мешает читать.
Есть вариант более эффективный при большой нагрузке, пару месяцев назад видел в конфе.
...
Рейтинг: 0 / 0
Захват единственной записи
    #32027985
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Варяг
Вы пытаетесь использовать подходы xBase в SQL, что несколько ненормально. Отсюда Ваше желание использовать курсор, который нужен совершенно для другого (честно говоря практически и не нужен, за редким исключением).
Необходимо менять логику. В SQL в принципе нет механизмов "надёжного удержания записи". Но зато есть возможность реализовать нечто подобное. Вы совершенно напрасно с ходу отвергли П1, который предложил ВладимирМ. Задумайтесь всё-таки над ним.
Вам выше предлагали способы блокировки записей, в принципе они рабочие(2000-й блокирует на уровне записи и 7-й по-моему тоже). Но не стоит ими пользоваться, это просто притягивание возможностей SQL под Ваши желания.

Что касается Вашего вопроса Можно ли определить, что эта запись уже кем-то прихвачена? , то наверное нельзя, поскольку такого действия как "прихватывание записи" нет. Меняйте логику работы с БД.

С приветом Сергей
...
Рейтинг: 0 / 0
Захват единственной записи
    #32028011
Александр Третьяков
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я делал блокировку по такому алгоритму:
1) добавил поле в таблицу username varchar(25) default ''
2) когда вибираю данные (открываю накладную, делаю с помощью хранимой процедуры) проверяю если пустое поле то я один с ним работаю, присвоюю свой user_name(), если не пустое то с ней работает пользователь имя его в username,
3) когда выхожу из накладной, присваиваю username=''

плюсы быстрота выполнения!!!!!,
минусы во время работы с накладной пропала связь и накладная осталась заблокированой (ввел кнопочку "разблокиравать", эта кнопочка появляеться для людей которые имеют соответствующие права (роль на сервере unloc_nakladna_role))

сейчас думаю что надо было добавить поле userid int, вместо username, всеже есть разница 4 байта и 28, економия 14 байт
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Захват единственной записи
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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