Нужно написать программку на VC++, которая бы обеспечивала доступ к базе данных, но основная сложность, для меня, представляет синхронизация данных в этой БД.
Т.е. если несколько юзеров будут INSERT'ить SELECT'ить UPDATE'ить одну и ту же базу,
одновременно, у некоторых будут неправильные данные.
Число юзеров не более 5 человек.
Как по науке решается вопрос о синхронизации? Может какие-то примеры?
И какую БД лучше использовать для этих нужд?
Здравствуйте Grog13M, Вы писали:
GM>Приветствую.
GM>Нужно написать программку на VC++, которая бы обеспечивала доступ к базе данных, но основная сложность, для меня, представляет синхронизация данных в этой БД.
GM>Т.е. если несколько юзеров будут INSERT'ить SELECT'ить UPDATE'ить одну и ту же базу, GM>одновременно, у некоторых будут неправильные данные.
Нет конечно. Если база не совсем г*. Рекомендую почитать что-нибудь типа "Реляционные БД для чайников". GM>Число юзеров не более 5 человек.
GM>Как по науке решается вопрос о синхронизации? Может какие-то примеры?
Главное ключевое слово — ACID (Atomicity, Consisteny, Isolation, Durability). Второе ключевое слово — transaction. GM>И какую БД лучше использовать для этих нужд?
Ту, которая поддерживает транзакции. Почти все современные СУБД это делают. Никаких усилий (почти) по синхронизации приложений не потребуется.
GM>Спасибо.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
GM>>Как по науке решается вопрос о синхронизации? Может какие-то примеры? S>Главное ключевое слово — ACID (Atomicity, Consisteny, Isolation, Durability). Второе ключевое слово — transaction. GM>>И какую БД лучше использовать для этих нужд? S>Ту, которая поддерживает транзакции. Почти все современные СУБД это делают. Никаких усилий (почти) по синхронизации приложений не потребуется.
Ага, я понял, принцип транзакции "либо все, либо ничего"
После того как юзер сделал COMMIT, то любые другие юзеры при SELECT'ах увидят измененное состояние, если СЕЛЕКТ был после КОММИТА и предыдущее состояние если до?
Т.е. в самом приложении ничего по синхронизации данных делать не надо? Или?
Порекомендуйте, пожалуйста, какую-нибудь простенькую БД, с возможностью транзакций.
Стоять это все будет по Win2000 или WinXP.
Здравствуйте Grog13M, Вы писали:
GM>Здравствуйте Sinclair, Вы писали:
GM>>>Как по науке решается вопрос о синхронизации? Может какие-то примеры? S>>Главное ключевое слово — ACID (Atomicity, Consisteny, Isolation, Durability). Второе ключевое слово — transaction. GM>>>И какую БД лучше использовать для этих нужд? S>>Ту, которая поддерживает транзакции. Почти все современные СУБД это делают. Никаких усилий (почти) по синхронизации приложений не потребуется.
GM>Ага, я понял, принцип транзакции "либо все, либо ничего" GM>После того как юзер сделал COMMIT, то любые другие юзеры при SELECT'ах увидят измененное состояние, если СЕЛЕКТ был после КОММИТА и предыдущее состояние если до?
Ну, то что на самом деле увидят усеры сильно зависит от так называемого "уровня изоляции" транзакций, в которых они находятся и от используемой модели поддержки кислотности. Например, при дефолтной изоляции (Read Committed) в MS SQL Server усеры, пытающиеся сделать селект по данным, которые сейчас кто-то пишет, будут вынуждены ждать коммита. А вот в interbase, например. они действительно увидят предыдущее состояние.
GM>Т.е. в самом приложении ничего по синхронизации данных делать не надо? Или?
Да. Ничего делать не надо. Прежде всего потому, что дело это дюже сложное, и в стандартные БД встроено более чем достаточно возможностей для поддержки всех типичных сценариев синхронизации.
GM>Порекомендуйте, пожалуйста, какую-нибудь простенькую БД, с возможностью транзакций. GM>Стоять это все будет по Win2000 или WinXP.
Гм. Увы, я не спец в этих вопросах. По идее, MS Access должен это все уже уметь — лень читать доку.
А так, под виндою, я считаю, лучче MS SQL нету. Тем более теперь он даже в CE варианте есть, то ись совсем нетребовательный зверек.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте Grog13M, Вы писали:
GM>Здравствуйте Sinclair, Вы писали:
GM>Порекомендуйте, пожалуйста, какую-нибудь простенькую БД, с возможностью транзакций. GM>Стоять это все будет по Win2000 или WinXP.
я бы так распределил (любое деление, конечно, условно):
персональные БД — MSAccess
начального уровня — mySQL
среднего — Interbase или Sybase Anywhere
высокого — Sybase Enterprise, MSSQL
очень высокого — Oracle, Progress
Здравствуйте Grog13M, Вы писали:
GM>Здравствуйте Sinclair, Вы писали:
GM>Порекомендуйте, пожалуйста, какую-нибудь простенькую БД, с возможностью транзакций. GM>Стоять это все будет по Win2000 или WinXP.
В твоем случае лучший вариант Interbase, в кратце почему:
1. На небольшом числе активных коннектов (до 100 ) очень быстрая (ИМХО сделает ORACLE) и надежная СУБД, работает с большимими объемами данных > 2Гб (на два куска)
2. Кросс платформенность, сразу же рекомендую переходить на Linux там есть Interbase classic server.
3. Легко настраивается, практически plug&play.
4. Поддерживает и наиболее соответствует T-SQL.
5. Если Делфи-ец — есть в VCL компоненты прямого доступа IBX, для C/С++ precompiler или писать на API что тоже клево.
6. рускоязычный сайт ib.demo.ru c Димой Кузьменко /*мое почтение*/ (но кажется он сменил положение)
7. У 6-й версии открыт исходный код.
8. 6-я версия бесплатна
учитывая все это можно разработать качественную клиент-серверную БД с очень низкой себестоимостью (IB_CS_LI_6.x + RH Linux 7.2)
минусы:
1. Изначально развивалась как малая СУБД, отсюда и все минусы (не использует SMP под Вынь и др.)
Здравствуйте Sinclair, Вы писали:
S>Здравствуйте Grog13M, Вы писали:
GM>>Здравствуйте Sinclair, Вы писали:
GM>>>>Как по науке решается вопрос о синхронизации? Может какие-то примеры? S>>>Главное ключевое слово — ACID (Atomicity, Consisteny, Isolation, Durability). Второе ключевое слово — transaction. GM>>>>И какую БД лучше использовать для этих нужд? S>>>Ту, которая поддерживает транзакции. Почти все современные СУБД это делают. Никаких усилий (почти) по синхронизации приложений не потребуется.
GM>>Ага, я понял, принцип транзакции "либо все, либо ничего" GM>>После того как юзер сделал COMMIT, то любые другие юзеры при SELECT'ах увидят измененное состояние, если СЕЛЕКТ был после КОММИТА и предыдущее состояние если до? S>Ну, то что на самом деле увидят усеры сильно зависит от так называемого "уровня изоляции" транзакций, в которых они находятся и от используемой модели поддержки кислотности. Например, при дефолтной изоляции (Read Committed) в MS SQL Server усеры, пытающиеся сделать селект по данным, которые сейчас кто-то пишет, будут вынуждены ждать коммита. А вот в interbase, например. они действительно увидят предыдущее состояние.
GM>>Т.е. в самом приложении ничего по синхронизации данных делать не надо? Или? S>Да. Ничего делать не надо. Прежде всего потому, что дело это дюже сложное, и в стандартные БД встроено более чем достаточно возможностей для поддержки всех типичных сценариев синхронизации.
GM>>Порекомендуйте, пожалуйста, какую-нибудь простенькую БД, с возможностью транзакций. GM>>Стоять это все будет по Win2000 или WinXP. S>Гм. Увы, я не спец в этих вопросах. По идее, MS Access должен это все уже уметь — лень читать доку. S>А так, под виндою, я считаю, лучче MS SQL нету. Тем более теперь он даже в CE варианте есть, то ись совсем нетребовательный зверек.
А скажите, поддерживает ли механизм транзакций такие возможности:
представим себе две связанные таблицы (один-ко-многим), допустим, накладная — перечень товаров. Один юзер выбрал запись с накладной номер NN, считал через SELECT перечень находящихся в ней товаров и редактирует этот перечень.
Второй юзер, не ведая того, что накладную NN выбрал первый, тоже считал ее и редактирует, хотя вроде как и не имеет на это право.
Есть ли возможность сообщить юзеру №2, что, хотя он прочел накладную NN, он не имеет право ее редактировать? Есть ли возможность сообщить юзеру №2, кто в данный момент редактирует накладную NN из других пользователей?
Или механизм транзакций может только сообщить юзеру №2 при сохранении накладной, что все изменения, которые он сделал, недействительны, так как данная запись "была изменена другим пользователем"?
Здравствуйте Al-Ko, Вы писали:
AK>А скажите, поддерживает ли механизм транзакций такие возможности:
AK>представим себе две связанные таблицы (один-ко-многим), допустим, накладная — перечень товаров. Один юзер выбрал запись с накладной номер NN, считал через SELECT перечень находящихся в ней товаров и редактирует этот перечень. AK>Второй юзер, не ведая того, что накладную NN выбрал первый, тоже считал ее и редактирует, хотя вроде как и не имеет на это право.
AK>Есть ли возможность сообщить юзеру №2, что, хотя он прочел накладную NN, он не имеет право ее редактировать? Есть ли возможность сообщить юзеру №2, кто в данный момент редактирует накладную NN из других пользователей?
AK>Или механизм транзакций может только сообщить юзеру №2 при сохранении накладной, что все изменения, которые он сделал, недействительны, так как данная запись "была изменена другим пользователем"?
Значит, так. Вышеобсужденная кислотность (ACIDity) может достигаться различными способами. В основном различают два: pessimistic locking и optimistic locking.
Суть пессимистичной блокировки состоит в тоследующем: мы предпочитаем "раннее оповещение" о возможных конфликтах. Поэтому объект, к которому осуществляется доступ, блокируется таким образом, чтобы никто другой не мог выполнить конфликтующую операцию. То есть мы зашли в домик, дверь заперли и сидим, пока не закончим. Тот, кто попытается зайти туда же, получит от ворот поворот. В вышеприведенном примере это означает, что второй юзер просто не сможет отредактировать накладную NN.
Блокировки в такой системе бывают трех типов: Shared, Update, Exclusive.
Когда клиент (точнее, транзакция) пытается запросить какой-либо вид лока на определенный объект, то успех или неуспех операции зависит от наличия существующего лока на тот же объект, созданного другой транзакцией. В следующей таблице в столбцах идут существующие локи, а каждая строка соответствует запрашиваемому типу:
Плюсик означает, что операция будет успешна. Как видно, матрица имеет диагональный вид. Это естественно — совместимость локов штука симметричная. Смысл этой таблички в том, что те, кто хотят читать данные, получают перед этим shared lock. Из таблички видно, что они обломятся только в том случае, если кто-то уже захватил exclusive лок — это означает, что в данные прямо сейчас идет запись, и читать их нельзя. Все остальные виды локов, имеющиеся на объекте, не мешают нашему чтению.
Те, кто собирается писать данные, должны сначала получить exclusive lock, чтобы убедиться, что они никому не мешают. Такой лок не совместим ни с кем, и может быть выдан только один одновременно.
Промежуточный update lock введен в систему для того, чтобы решить такую проблему: когда кто-то сначала читает данные, а потом пытается их же писать. Если две таких транзакции выполняются одновременно (а это весьма вероятно, т.к. множество клиентов скорее всего будут выполнять однотипные действия), то у них будет хороший шанс зажать друг друга в угол. Дело в том, что если запрошенный лок конфликутет с уже имеющимися, то по умолчанию транзакция неопределенно долго ожидает снятия локов. Так что две транзакции спокойно получат по shared локу и каждая попытается сконвертировать его в exclusive. Но каждая сможет продолжить свою работу только после того, как другая отпустит shared lock. Итого — deadlock. Упс. Всех расстрелять.
Получение сразу exclusive лока не есть хорошо, поскольку если мы первые 90% процентов времени в транзакции тратим на чтение и 10% на запись, то 9/10 времени мы не даем другим доступа безо всякой к тому причины.
Глядя на схему совместимости update лока, можно понять для чего он предназначен. Он все еще дает остальным читать данные, но не даст никому ни писать, ни получить аналогичный лок, гарантируя успешное получение exclusive лока позднее.
Итак, с вами были пессимистичные блокировщики.
Далее в нашей программе — optimistic locking.
Эта стратегия на первый взгляд не похожа на блокировку вообще. Дело в том, что мы "запираем" данные только в момент commit транзакции, а длительные подготовки к этому моменту делаются безо всяких проверок конкурирующего доступа.
Ключевым фактором в оптимистичной блокировке является детектирование произошедших изменений.
Алгоритм коммита таков:
1. Проверить все данные, которые мы читали в транзакции, на наличие изменений с тех пор.
2. Если обнаружены изменения, то результат наших действий некорректен. Производим rollback, т.е. все изменения отменяются.
3. Если изменений не обнаружено, то можно сохранять изменения транзакции, делая их видимыми для окружающих.
Реализация этого алгоритма сделана по разному в разных системах. Например, в Interbase в саму структуру базы встроено отслеживание изменений в читаемых кем-либо данных. В MS SQL Server это делается при помощи сочетания timestamp-полей, которые гарантированно изменяют свое значение при хаписи в таблицу, и кратковременных пессимистичных блокировок в момент коммита (надо сказать, что сам сервер предоставляет только самый низкий уровень поддержки. Чтобы реализовать OL-систему на его основе, надо изрядно попотеть).
Резюме:
В вышеописанной ситуации картина для пользователей будет примерно такой, в зависимости от типа используемых блокировок:
1. Пессимистичные блокировки:
1.1. Немедленный откат: Потльзователь 2 получает при попытке зачитать накладную Упс! Объект зблокирован.
1.2. Бесконечное ожидание У Пользователя 2 прога виснет при чтении до тех пор, пока Пользователь 1 не сохранит/отменит свои изменения. После этого Пользователь 2 увидит корректное финальное состояние данных.
1.3. Конечное ожидание. Прога повисит некоторое время, и либо выпадет результат 1.1, либо 1.2, в зависимости от тормознутости Пользователя 1.
Резюме пессимистичных блокировок: Кто первым встал, того и тапки. Все проблемы касаются только Пользователя 2.
2. Оптимистичные блокировки:
Оба Пользователя увидят одну и ту же версию накладной — исходную. Дальнейший результат зависит от того, в каком порядке и какие действия они выполняют:
2.1. Пользователь 2 всего лишь хотел посмотреть чегой-то в этой накладной. Увидел, закрыл. Пользователь 1 ничего не заметил
2.2. Пользователь 2 шустро что-то поменял и сохранил накладную. Пользователь 1 при попытке сохранить накладную (но не раньше!) увидит "Изменения недействительны"
2.3. Пользователь 2 залез и начал что-то менять. Пользователь 1 сохранил накладную. Пользователь 2 при попытке сохранить получит тот же отказ "Изменения недействительны".
Таким образом:
1. При пессимистичных блокировках придется ждать, пока объект отпустят, даже если хотелось "всего лишь посмотреть"
2. При оптимистичных блокировках нет никакой возможности проверить, а не случилось ли страшное (кроме как истерично сохраняться каждые 20 секунд, надеясь подловить конкурента)
На самом деле, привденный пример реализации пессимизма слишком мрачен — при правильном управлении блокировками (shared->update->exclusive) можно добится высокой степени одновременности работы, все еще избегая потери изменений. Просто я и так чего-то увлекся... Люблю я эти вещи... транзакции, блокировки... кэши, индексы... оптимизация планов запросов, двухфазный коммит...
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте Sinclair, Вы писали:
S>Здравствуйте Al-Ko, Вы писали:
AK>>А скажите, поддерживает ли механизм транзакций такие возможности:
AK>>представим себе две связанные таблицы (один-ко-многим), допустим, накладная — перечень товаров. Один юзер выбрал запись с накладной номер NN, считал через SELECT перечень находящихся в ней товаров и редактирует этот перечень. AK>>Второй юзер, не ведая того, что накладную NN выбрал первый, тоже считал ее и редактирует, хотя вроде как и не имеет на это право.
AK>>Есть ли возможность сообщить юзеру №2, что, хотя он прочел накладную NN, он не имеет право ее редактировать? Есть ли возможность сообщить юзеру №2, кто в данный момент редактирует накладную NN из других пользователей?
AK>>Или механизм транзакций может только сообщить юзеру №2 при сохранении накладной, что все изменения, которые он сделал, недействительны, так как данная запись "была изменена другим пользователем"?
Извините за SKIPPED — это самая классная статья по транзакциям, которая мне попадалась. Но...
Что pessimistic, что optimistic — такая реализация одновременного доступа только лишь с помощью транзакций не позволяет "спокойно" работать с такой простейшей базой данных, которая приведена в моем примере. У нас в сети всего три (очень редко четыре) компьютера, и между ними иногда происходят конфликты, связанные с одновременным доступом. Правильно, или ты ждешь неизвестно сколько, пока запись не освободится, или ты получаешь откат после вдумчивого редактирования накладной с пояснением, что ты не имеешь, оказывается, право эту накладную редактировать.
Пришлось искать какой-то выход из положения. Ничего лучшего не придумав, в базу данных пришлось ввести служебную таблицу (назовем ее условно LOCKER), которая содержит в себе все имеющиеся на данный момент блокировки. Она выглядит примерно так:
User Table Info(номер блокированного документа)
=================================================================
1 INVOICE 56
1 ORDER 12
2 INVOICE 55
3 INVOICE 57
итак, пользователь 1 зашел в накладную 56. При этом он может редактировать эту накладную, либо пить кофе в другой комнате (что тоже иногда встречается). Пользователь N, заходя в накладную 56, получает информацию из таблицы LOCKER, что накладная 56 заблокирована пользователем 1. Он может читать из накладной 56 информацию, но никогда не начнет ее бесполезное редактирование. Как только пользователь 1 ушел с накладной 56, в таблице LOCKER исчезла эта строка("1 INVOICE 56") и накладная свободна для других пользователей. Вот в моменты записи/чтения в таблицу LOCKER транзакции просто доктор прописал — эти моменты столь кратковременны, что пессимистичная блокировка не видна для пользователей.
Иначе — бесконечные непонятки между пользователями.
[безжалостно skipped]
AK>Что pessimistic, что optimistic — такая реализация одновременного доступа только лишь с помощью транзакций не позволяет "спокойно" работать с такой простейшей базой данных, которая приведена в моем примере. У нас в сети всего три (очень редко четыре) компьютера, и между ними иногда происходят конфликты, связанные с одновременным доступом. Правильно, или ты ждешь неизвестно сколько, пока запись не освободится, или ты получаешь откат после вдумчивого редактирования накладной с пояснением, что ты не имеешь, оказывается, право эту накладную редактировать.
AK>Пришлось искать какой-то выход из положения. Ничего лучшего не придумав, в базу данных пришлось ввести служебную таблицу (назовем ее условно LOCKER), которая содержит в себе все имеющиеся на данный момент блокировки. Она выглядит примерно так:
AK>User Table Info(номер блокированного документа) AK>================================================================= AK>1 INVOICE 56 AK>1 ORDER 12 AK>2 INVOICE 55 AK>3 INVOICE 57
AK>итак, пользователь 1 зашел в накладную 56. При этом он может редактировать эту накладную, либо пить кофе в другой комнате (что тоже иногда встречается). Пользователь N, заходя в накладную 56, получает информацию из таблицы LOCKER, что накладная 56 заблокирована пользователем 1. Он может читать из накладной 56 информацию, но никогда не начнет ее бесполезное редактирование. Как только пользователь 1 ушел с накладной 56, в таблице LOCKER исчезла эта строка("1 INVOICE 56") и накладная свободна для других пользователей. Вот в моменты записи/чтения в таблицу LOCKER транзакции просто доктор прописал — эти моменты столь кратковременны, что пессимистичная блокировка не видна для пользователей.
AK>Иначе — бесконечные непонятки между пользователями.
Все правильно! Таким образом, вы реализовали чистейшей воды Pessimistic Locking. Таблица LOCKER используется как менеджер локов.
Недостатоки такого подхода:
— все приложения обязаны быть "вежливыми" и не забывать посмотреть в эту таблицу.
— если пользователь заблокировал накладную, пошел пить кофе, отравился и умер, то накладная останется заблокированной навсегда.
Достоинтство: Легким движением руки можно добавить возможность административного вмешательства. Например, менеджер или там администратор может "сломать" замок, поставленный нерадивым пользователем.
Теперь о том, как все это можно было бы сделать поверх базы данных, которая поддерживает pessimistic locking:
0. Мы отключаем ожидание разблокирования по умолчанию
1. Когда мы открываем накладную, мы ставим на нее shared lock (в случае неудачи сразу сообщаем пользователю, что прямо сейчас кто-то пишет)
2. Когда пользователь пытается начать редактирование, мы переводим shared lock в update lock. Если нам это не удается, значит кто-то уже начал редактирование.
3. Теперь полоьзователь долго и вдумчиво редактирует накладную. Все могут спокойно читать, но пункт 2 никто из них не пройдет.
4. Наконец, пользователь давит "сохранить". В этот момент мы пытаемся получить exclusive lock, и нам придется подожлать, пока все дочитают. Но нам точно известно, что именно мы получим возможность записать данные, а не кто-то другой.
5. Все, запись удалась, можно жить дальше.
Возможная модификация: для чтения мы получаем shared lock и сразу же его отпускаем, чтобы не создавать другим задержек на шаге 4. При выполнении шага 2 мы перечитываем данные, чтобы учесть возможные изменения, произошедшие между 1 и 2.
Преимущество такого подхода в том, что мы защищены от негодяев средствами сервера. Во-первых, он не даст нарушить блокировку никому другому, даже если он ничего не знает про наши соглашения. Во-вторых, если клиентская программа упала, то все блокировки будут автоматически отпущены.
Как реализовать подобное поведение средствами MS SQL Server я знаю — нужно всего лишь покопаться в настройках lock timeout, и применять некоторое шаманство с set transaction isolation level или хинтами в select-ах. Насчет других серверов пришлось бы покопать доки пару дней.
Если интересны подробности реалтзации такого щастья для MSSQL — могу написать. Кстати, можно даже отловить, кто именно нас заблокировал (в смысле идентификатор пользователя), и, если применяется WinNT Autentification, то послать ему мессагу через Messenger Service.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
...
S>Как реализовать подобное поведение средствами MS SQL Server я знаю — нужно всего лишь покопаться в настройках lock timeout, и применять некоторое шаманство с set transaction isolation level или хинтами в select-ах. Насчет других серверов пришлось бы покопать доки пару дней.
S>Если интересны подробности реалтзации такого щастья для MSSQL — могу написать. Кстати, можно даже отловить, кто именно нас заблокировал (в смысле идентификатор пользователя), и, если применяется WinNT Autentification, то послать ему мессагу через Messenger Service.
Что использую: MS SQL 2005 Express + Delphi DBE
Что делаю: прогу которая пользует базу заведенную в этом самом MSSQL в многопользовательском режиме (с базой будут работать только при помощи моей проги).
Губокого знания транзакций, тригеров и прочей святотени серверов БД не имею, писал раньше в основном однопользовательские проги...
Что Хочется:
1) если один пользователь уже работает с записью, т.е. не просто смотрит, а именно меняет ее, то чтобы другой пользователь при открытии данной записи мог узнать, что над этой записью уже кто-то корпит (и желательно узнать кто именно, один или несколько — зная кто корпит можно узнать за какие именно поля он отвечает)
2) если за время работы пользователя над записью, кто-то ее по тихому поменял, то в моментнепосредственно внесенния изменений пользователь должен знать о том, что запись поменяли (желательно знать кто именно, один или несколько, но не обязательно)
У меня проблема следующего рода:
при одновременной работе нескольких экземпляров программ — они могут редактировать одну и туже запись даже не зная об этом — никаких ошибок при этом не возникает. — отсюда я сделал вывод что имеем дело с вариантом optimistic.
как я не пытался, так и не смог найти как же перейти в режим pessimistic ни в настройках сервака и базы, ни в свойствах компонент — нет ничего подобного (напомню, используется BDE, а не ADO). В ADO нашел свойство LockType у компонента TADOTable, выставил в pessimistic, но после открытия таблицы LockType сам переходит в состояние BatchOptimistic, на этом мое знакомство с ADO пока закончилось... Далее с BDE...
В BDE дошел до использования его внутренних функции:
DbiIsRecordLocked — при помощи этой функции можно проверить блокировку записи
DbiGetRecord — выставить записи WRITELOCK
DbiRelRecordLock — снять LOCK
DbiOpenLockList — открыть список всех блокировок
дык вот, перед тем как начать изменять запись пытаюсь проверить нет ли блокировки (DbiIsRecordLocked) — говорит нету, проверяю какие у нас имеются блокировочки(DbiOpenLockList) — никаких нема, ну нету и хорошо(смотрю в мониторе сервака-действительно нету), после того как вошел в режим записи опять проверяю нет ли блокировки (DbiIsRecordLocked) — говорит есть, проверяю какие у нас имеются блокировочки(DbiOpenLockList) — смотрю действительно есть одна, ну хорошо думаю, лезу в монитор сервака- как не было, так и нету блокировок((, ну и соответственно после Cancel и после Post проверяю блокировки и если есть снимаю...
вот такая грустная история...
Подытожим:
Стоит ли перейти с BDE на ADO, чем он лучше???
Как и где можно выставить Lock режим (pessimistic,optimistic)???
Как узнать редактирует кто-либо (и кто именно) сейчас запись или нет (что нужно доработать и как это лучше сделать)???
Как узнать была ли изменена запись с того момента как юзверь начал ее тиранить и если да, то кем (что нужно доработать и как это лучше сделать)???
Буду очень благодарен, если поможете...
ну а пока буду сам искать-ковырять
Здравствуйте, MASReady, Вы писали: MAS>Подытожим: MAS>Стоит ли перейти с BDE на ADO, чем он лучше???
Не имеет значения. Управление блокировками все равно придется делать вручную. MAS>Как и где можно выставить Lock режим (pessimistic,optimistic)???
При работе на уровне датасетов вся блокировка оптимистическая, хоть и некорректная. MAS>Как узнать редактирует кто-либо (и кто именно) сейчас запись или нет (что нужно доработать и как это лучше сделать)???
Нужно сделать все вручную:
— перед началом редактирования вызвать sp_get_app_lock, придумав достаточно уникальный идентификатор записи
— если вернулось значение, говорящее об истечении таймаута, можно подсмотреть во view sys.dm_tran_locks идентификатор виновной сессии и узнать через sys.sysprocesses кто ее инициировал.
MAS>Как узнать была ли изменена запись с того момента как юзверь начал ее тиранить
Для этого к таблице нужно добавить поле типа timestamp. Оно всегда меняется при изменении записи. MAS>и если да, то кем (что нужно доработать и как это лучше сделать)???
Нет, этого сделать нельзя. Доработать можно при помощи триггера, который запишет в нужное место значение DATABASE_PRINCIPAL_ID()
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Значит, так. Вышеобсужденная кислотность (ACIDity) может достигаться различными способами. В основном различают два: pessimistic locking и optimistic locking.
А скажите, пожалуйста, виды блокировок — это свойство сервера, соединения, транзакции, системы или ещё чего?
Здравствуйте, individual, Вы писали: I>А скажите, пожалуйста, виды блокировок — это свойство сервера, соединения, транзакции, системы или ещё чего?
Свойство блокировок.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
I>>А скажите, пожалуйста, виды блокировок — это свойство сервера, соединения, транзакции, системы или ещё чего? S>Свойство блокировок.
Я хотел узнать следующее. В клиентском приложении происходят события типа connect, begin transaction, отправка SQL-запроса, disconnect. В какой момент я определяю, какая у меня будет блокировка и как?
I>>>А скажите, пожалуйста, виды блокировок — это свойство сервера, соединения, транзакции, системы или ещё чего? S>>Свойство блокировок.
I>Я хотел узнать следующее. В клиентском приложении происходят события типа connect, begin transaction, отправка SQL-запроса, disconnect. В какой момент я определяю, какая у меня будет блокировка и как?
При неявном использовании блокировок
блокировками управляет сама транзакция
IMHO этот подход предпочтительнее...
В MSSQL есть 2 способа:
1) Перед началом транзакции через
SET TRANSACTION ISOLATION LEVEL ...
2) В самой транзакции для конкретного оператора можно указать
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, individual, Вы писали: I>>А скажите, пожалуйста, виды блокировок — это свойство сервера, соединения, транзакции, системы или ещё чего? S>Свойство блокировок.
Смотря что понимается под словом "виды"
Если говорить о методе реализации (Какой ресурс блокирует и когда)
то это свойство сервера
Здравствуйте, MASReady, Вы писали:
MAS>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, MASReady, Вы писали:
S>>Уехал в командировку, отвечу как вернусь.
MAS>Ай как жалко
MAS>посоветуйте книжечку или где порыться в инете, мож сам разберусь, мне за несколько дней нужно все сделать
Нужно знать возможности СУБД под которую программируешь,
это не только я так считаю — известный эксперт по Oracle
Том Кайт того же мнения
Так что читать нужно Books Online к MS SQL 2005
Или доку по MS SQL 2000
Например:
MCAD/MCSE/MCDBA Self-Paced Training Kit: Microsoft SQL
Server 2000 Database Design and Implementation, Exam 70-229,
Это довольно простое описание.
Существует русское издание
+ что-то типа
A First Look at SQL Server 2005 for Developers
by Bob Beauchemin,Niels Berglund,Dan Sullivan
(ISBN: 0-321-18059-3)
Для твоей задачи IMHO эта книга имеет смысл если будешь
заморачиваться с версионностью
ПО T-SQL рекомендую:
Henderson, Kenneth W.The guru's guide to Transact-SQL
... MAS>>Как узнать была ли изменена запись с того момента как юзверь начал ее тиранить S>Для этого к таблице нужно добавить поле типа timestamp. Оно всегда меняется при изменении записи. MAS>>и если да, то кем (что нужно доработать и как это лучше сделать)??? S>Нет, этого сделать нельзя. Доработать можно при помощи триггера, который запишет в нужное место значение DATABASE_PRINCIPAL_ID()
...
спасибо за ответ!!!
Я в принципе со всем разобрался кроме получении имени пользователя который заблокировал запись и компутера с которого он это сделал, сейчас над этим и работаю...
единственная проблема была с созданием процедуры, которая по имени таблицы (@tablename) и уникальному @ID записи должна была вернуть timestamp-поле, у меня не получалось сделать запрос указывая в запросе имя таблицы при помощи переменной (входного параметра) @tablename(//*--SELECT TOP 1 @SYSROWCHANGED=SYSROWCHANGED FROM @tablename WHERE ID=@id--*//), оказывается на языке MS SQL надо явно указывать имя таблицы, ну или я что-то недопонял... пришлось делать по другому: формировать строку запросапередавать ее в sp_executesql и получать от нее курсор, а уже из курсора потом вытягиваю переменную...
как-то это все кривовато, но по другому не получилось, а из проги как-то не хочется каждый раз запросом это дело доставать...
если можешь напиши подробнее свои измышления по поводу пользователя и компа с которого заблокирована запись...
Спасибо за совет!
То, что нужно знать — это понятно и бесспорно!!!
Но у меня не было ни книг, ни времени, ни даже инет трафа, чтобы скачать books online но к счастью у меня есть MSDN там в принципе можно накопать какой-никакой материал, правда он от января 2006 и про SQL server 2005 и его особенности там мало, но основные функции там описаны, но естественно нужна не только справочная информация, сколько грамотно построенный учебник нацеленный как-раз на постижение "всей глубины наших глубин"
И при всем этом у меня есть достаточно глубокие знания в различных языках программирования которые и помогли мне в короткие сроки разобраться с этим делом и написать работающую прогу, которая в принципе удовлетворяет поставленным требованиям.
Но так как действовать пришлось больше по интуиции и по аналогии с другими языками, то скорей всего не обойденных "подводных камней" осталось немало, посему буду изучать и читать, постараюсь найти указанные тобой книжки...
Хочу еще, если запись уже заблокирована другим экемпляром моего приложения получить имя пользователя и комп с которых это было сделано... сейчас над этим и работа... причем хочу сделать основываясь на возможностях сервака, а не на его доработке...
Я сначала механизм отслеживания изменения записи за время редактирования сделал при помощи своего поля, но с этим было гораздо больше мороки, чем с использованием timestamp-поля...
Я так думаю писаль сервак не дураки и многое, тем более такие первостепенные вещи давно реализованы, нужно знать как...
Многие вещи по MS SQL нашел на этом форуме...
Здравствуйте, individual, Вы писали: I>Я хотел узнать следующее. В клиентском приложении происходят события типа connect, begin transaction, отправка SQL-запроса, disconnect. В какой момент я определяю, какая у меня будет блокировка и как?
По-разному. Вот, к примеру, для interbase ты выбираешь оптимистичные блокировки сразу при выборе СУБД. Для MS SQL 2000 — ты выбираешь пессимистичные при выборе СУБД. Для MS SQL 2005 ты выбираешь режим в любой момент перед каждой транзакцией.
Судя по всему, ты задаешь не те вопросы, ответы на которые тебе нужны. Постарайся задать более развернутый вопрос.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, 191540, Вы писали:
1>Если говорить о методе реализации (Какой ресурс блокирует и когда) 1>то это свойство сервера
Не обязательно. MS SQL 2005 поддерживает как pessimistic, так и optimistic locking.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>По-разному. Вот, к примеру, для interbase ты выбираешь оптимистичные блокировки сразу при выборе СУБД. Для MS SQL 2000 — ты выбираешь пессимистичные при выборе СУБД. Для MS SQL 2005 ты выбираешь режим в любой момент перед каждой транзакцией. S>Судя по всему, ты задаешь не те вопросы, ответы на которые тебе нужны. Постарайся задать более развернутый вопрос.
Вовсе нет! Вы с 191540 ответили именно на то, что я спрашивал!
А если более развёрнуто, то интересно узнать ещё следующее. Ты писал про три типа пессимистичных блокировок: Shared, Update, Exclusive. Их я тоже волен выбирать сам? Т.е. я могу сам выбрать, что заблокировать (какие таблицы или их части) и в каком режиме? Если да, то как это делается, например, в MS SQL или в Oracle?
И ещё: можно ли выбирать типы блокировок в Oracle (по умолчанию, я так понимаю, там оптимистичные блокировки)?
Здравствуйте, 191540, Вы писали:
1>Смотря что понимается под словом "виды"
Здесь я имел в виду модель optimistic locking или pessimistic locking.
1>Если говорить о методе реализации (Какой ресурс блокирует и когда) 1>то это свойство сервера
Здравствуйте, individual, Вы писали:
I>И ещё: можно ли выбирать типы блокировок в Oracle (по умолчанию, я так понимаю, там оптимистичные блокировки)?
Фраза "типы блокировок в Oracle" лишина смысла. Oracle это версионник, а не блокировочник. Там всё совсем по-другому.
Здравствуйте, individual, Вы писали: I>А если более развёрнуто, то интересно узнать ещё следующее. Ты писал про три типа пессимистичных блокировок: Shared, Update, Exclusive. Их я тоже волен выбирать сам? Т.е. я могу сам выбрать, что заблокировать (какие таблицы или их части) и в каком режиме? Если да, то как это делается, например, в MS SQL или в Oracle?
В определенных пределах — да. Напрямую, естественно, никакого управления нет. Но есть хинты, которые могут заставить изменить стратегию выдачи блокировок во время исполнения запроса. Крайне не рекомендую ими пользоваться. Единственное исключение — UPDLOCK, о нем догадаться оптимизатор не может. I>И ещё: можно ли выбирать типы блокировок в Oracle (по умолчанию, я так понимаю, там оптимистичные блокировки)?
Там оптимистичные блокировки на чтение, но, насколько я знаю, на модификацию там ставятся пессимистичные блокировки.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, 191540, Вы писали:
1>>Если говорить о методе реализации (Какой ресурс блокирует и когда) 1>>то это свойство сервера S>Не обязательно. MS SQL 2005 поддерживает как pessimistic, так и optimistic locking.
Вы меня не поняли.
1) pessimistic и optimistic locking это несколько иное. Это виды concurrency control[b]
2) То что Вы назвали действительно свойство сервера. так например мне не известно
о поддержке optimistic concurrency control в [b]MS SQL 2000
В Books Online и в MCAD/MCSE/MCDBA Self-Paced Training Kit: Microsoft SQL
Server 2000 Database Design and Implementation, Exam 70-229, Second Edition.
Есть упоминание, что optimistic concurrency control поддерживается в
MS SQL 2000 , но никаких примеров подтверждающих это я так и не нашел.
Я отношу это заявление на неточность в документации.
Кто знает — подскажите !!
3) Вообщето я имел ввиду какие обьекты СУБД затрагивает та или иная блокировка
(важно для понимания Эскалации, например) и какие же собственно блокировки вызывает
та или иная операция (помогает при оптимизации)
Здравствуйте, Блудов Павел, Вы писали:
БП>Здравствуйте, individual, Вы писали:
I>>И ещё: можно ли выбирать типы блокировок в Oracle (по умолчанию, я так понимаю, там оптимистичные блокировки)? БП>Фраза "типы блокировок в Oracle" лишина смысла. Oracle это версионник, а не блокировочник. Там всё совсем по-другому.
И "Да" и "Нет"
1) Да, действительно основная идея в Oracle это Multiversion concurrency control
2) Но это не всегда избавляет от блокировок. Достаточно посмотреть на
SELECT ... FOR UPDATE ...
3) Во многих СУБД есть несвойственные их каждодневному
способу использования средства для совместимости с др
СУБД
Здравствуйте, 191540, Вы писали:
1>Есть упоминание, что optimistic concurrency control поддерживается в 1>MS SQL 2000 , но никаких примеров подтверждающих это я так и не нашел. 1>Я отношу это заявление на неточность в документации.
Это заявление касалось MSSQL 2005.здесь
Здравствуйте, individual, Вы писали:
I>И ещё: можно ли выбирать типы блокировок в Oracle (по умолчанию, я так понимаю, там оптимистичные блокировки)?
Все несколько по другому. В Oracle используются пессимистические блокировки в основном внутренними механизмами. Oracle умеет сохранять консистентность в течении одного запроса что весьма пользительное свойство.
На момент запроса select, таблицу которую он затрагивает, блокируется shared блокировкой. Это защищает от изменения читаемых данных (но не блокирует другое чтение). После чтения, блокировка снимается.
На момент запроса insert, update или delete на таблицу накладывается блокировка shared row exclusive, а на строку exclusive. Это защищает таблицу от операций чтения, и операций DDL. Строку защищает от любого изменения. После изменения, блокировка снимается.
В случае операции DDL, ставится эксклюзивная блокировка на всю таблицу.
Есть некоторые исключения связанные с ссылочной целостностью, но в принципе все так.
На таблицы можно ставить блокировки самому (операция Lock Table).
На строки можно ставить только exclusive блокировки с помощью select ... for update. Но так как в Oracle неблокирующее чтение, то есть, блокировки на уровне строк при чтении никак не учитывается, то поведение отлично от блокировочников. select ... for update защищает только от операций update, delete, процедур DML, и других select ... for update.
Здравствуйте, 191540, Вы писали:
1>Кто знает — подскажите !!
У тебя вопросы... очень глобальные. Отвечать подробно — потянет на хорошую статью, да и не на одну. Отвечать буквально — будет либо неправильно, либо непонятно... Поэтому давай так, спрашивай не "что это за фича?", а "мне надо решить такую-то задачу.."