DataSet по ремоутингу - экземпляр или ссылка?
На мой взгляд нужно отдавать каждому клиенту свой набор данных, по следующим причинам:
1) Не передавать по сети весь набор для уменьшения нагрузки на транспорт (сколько клиент запросит, столько и "выслать").
2) Сихноронизировать ничего не нужно, при возврате измененных данных загружать их в БД, и т.к. это Remoting - оповещать подписанных клиентов на событие изменения. По повторному запросу клиента, если "он посчитает нужным" загружать их вновь.
3) Не нужно пытаться писать поддержку RDBMS, записывая изменения сразу в настоящую базу данных, а не в объекти хранящийся на сервере (поддержка транзакций, версионности, блокировок и т.д.)
Так что если не хотите усложнять задачу, и получить в конечном счете громоздкое решение взвесте все за и против :-)
Это точно :)
1) Не передавать по сети весь набор для уменьшения нагрузки на транспорт (сколько клиент запросит, столько и "выслать").
Т.е. имеется в виду, что каждый клиент получит отфильтрованный некоторым образов DataSet?
А если двое клинтов смотрят на одни и теже данные, при этом один меняет что-то, другой несколько позже меняет тоже самое (ведь он не увидит изменения, внесенные первым). Как разрешать такие конфликты?
Можно немножко этот момент пояснить.
ЗЫ Спасибо за советы :)
Т.е. имеется в виду, что каждый клиент получит отфильтрованный некоторым образов DataSet?
Да, именно, в любом случае придется передавать, например отчеты, кому-то будут нужны данные за весь период, кому-то за пару дней, другой дело можно организовать кэш, чтобы быстрее выбирать, но это немного другая история.
А если двое клинтов смотрят на одни и теже данные, при этом один меняет что-то, другой несколько позже меняет тоже самое (ведь он не увидит изменения, внесенные первым). Как разрешать такие конфликты?
Стандартная задача для СУБД (RDBMS).
Сложно ответить однозначно, в целом, тут как раз таки помогаю механизмы из следующего пункта, которые позволяют избежать конфликтов как таковых.
Знакома конструкция SELECT ... FOR UPDATE ?
Неплохое описание подобной проблеме дал Том Кайт (Tom Kyte) на примере:
...Рассмотрим следующий пример. Один разработчик показывал мне только что завершенную им программу планирования ресурсов (учебных классов, проекторов и т.д.), находящуюся в стадии внедрения. Это приложение реализовало бизнес-правило, предотвращающее выделение ресурса более чем одному лицу на любой период времени. То есть, приложение содержало специальный код, который проверял, что никто из пользователей не затребовал ресурс на тот же период времени (по крайней мере разработчик думал, что его код это проверяет). Код
обращался к таблице планов и, если в ней не было строк с перекрывающимся временным интервалом, вставлял в нее новую строку. Итак, разработчик просто работал с парой таблиц:
create table schedules(resource_name varchar2(25) references resources, start_time date,end_time date);
И прежде чем зарезервировать на определенный период, скажем, учебный класс, приложение выполняло запрос вида:
from schedules
where resource_name = :room_name
and (start_tiroe between :new_start_time and :new_end_time
or
end_time between :new_start_time and :new_end_time)
Он казался разработчику простым и надежным: если возвращено значение 0, учебный класс можно занимать; если возвращено ненулевое значение, значит, учебный класс на этот период уже кем-то занят. Ознакомившись с используемым алгоритмом, я подготовил простой тест, показывающий, какая ошибка будет возникать при реальной эксплуатации приложения. Эту ошибку будет крайне сложно обнаружить и тем более установить ее причину, — кому-то может даже показаться, что это ошибка СУБД.
Я предложил его коллеге сесть за соседний компьютер, перейти на тот же экран и попросил на счет три обоих нажать на кнопку Go и опытаться зарезервировать класс на одно то же время. Оба смогли это сделать — то, что прекрасно работало в изолированной среде, не сработало в среде многопользовательской. Проблема в этом случае была
вызвана неблокирующим чтением в Oracle. Ни один из сеансов не блокировал другой.
Оба сеанса просто выполняли представленный выше запрос и применяли алгоритм резервирования ресурса. Они оба могли выполнять запрос, проверяющий занятость ресурса,
даже если другой сеанс уже начал изменять таблицу планов (это изменение невидимо для других сеансов до фиксации, то есть до тех пор, когда уже слишком поздно). Поскольку сеансы никогда не пытались изменить одну и ту же строку в таблице планов, они никогда и не блокировали друг друга, вследствие чего бизнес-правило не срабатывало так, как ожидалось.
Разработчику необходим метод реализации данного бизнес-правила в многопользовательской среде, способ, гарантирующий что в каждый момент времени только один сеанс резервирует данный ресурс. В данном случае решение состояло в программном упорядочении доступа — кроме представленного выше запроса count(*), необходимо было сначала выполнить:
->>>select * from resources where resource_name = :room_name FOR UPDATE;
Ранее в этой главе рассматривался пример, когда использование конструкции FOR UPDATE приводило к проблемам, но в этом случае она обеспечивает корректную работу бизнес-правила. Мы просто блокируем ресурс (учебный класс), использование которого планируется непосредственно перед его резервированием, до выполнения зап-
роса к таблице планов, выбирающего строки для данного ресурса. Блокируя ресурс, который мы пытаемся зарезервировать, мы гарантируем, что никакой другой сеанс в это же время не изменяет план использования ресурса. Ему придется ждать, пока наша транзакция не будет зафиксирована — после этого он сможет увидеть сделанное в ней резервирование. Возможность перекрытия планов, таким образом, устранена. Разработчик должен понимать, что в многопользовательской среде иногда необходимо использовать те же приемы, что и при многопотоковом программировании. В данном случае конструкция FOR UPDATE работает как семафор. Она обеспечивает последовательный доступ к конкретной строке в таблице ресурсов, гарантируя, что два cеанса одновременно не резервируют ресурс.
Этот подход обеспечивает высокую степень параллелизма, поскольку резервируемых ресурсов могут быть тысячи, а мы всего лишь гарантируем, что сеансы изменяют конкретный ресурс поочередно. Это один из немногих случаев, когда необходимо блокирование вручную данных, которые не должны изменяться. Требуется уметь распознавать
ситуации, когда это необходимо, и, что не менее важно, когда этого делать не нужно (пример, когда не нужно, приведен далее). Кроме того, такой прием не блокирует чтение ресурса другими сеансами, как это могло бы произойти в других СУБД, благодаря чему обеспечивается высокая масштабируемость...
Думаю пример отвечает на вопрос? Попробуйте исходя из задачи, возложить максимум нагрузки на СУБД, возможности которой в частности в плане блокировки описаны в цитате, и упомяуты в третьем пункте моего сообщения :) , В примере нет промежуточного звена, и запросы идут напрямую, но в принципе опять же исходя из условий, можно оптимизировать это дело для трезвенной архитектуры. И не забывайте, что вы можете оповещать клиента событиями об изменениях - очень полезно :)
Книгу Тома Кайта можете взять тут, если заинтересовало.
Спасибо за советы :)
[QUOTE=http://www.sqlteam.com/article/row-locking]
"I wish to keep some rows locked on my sql7 table (so that nobody modifies them until i am finished with it) until my vb6 form in question is closed. I do not want to store any status code within the table (which calls for addl. maintenance, for eg if my w/s boots with the status code still set!) How do i achieve this rowlock for extended period of time? Any clues???" Yep, we can handle this one. We'll use some locking hints.
Change your SELECT statement to look something like this:
SELECT *
FROM authors
WITH (HOLDLOCK, ROWLOCK)
WHERE au_id = '274-80-9391'
/* Do all your stuff here while the record is locked */
COMMIT TRAN
The HOLDLOCK hint will instruct SQL Server to hold the lock until you commit the transaction. The ROWLOCK hint will lock only this record and not issue a page or table lock.
The lock will also be released if you close your connection or it times out. I'd be VERY careful doing this since it will stop any SELECT statements that hit this row dead in their tracks. SQL Server has numerous locking hints that you can use. You can see them in Books Online when you search on either HOLDLOCK or ROWLOCK.
[/QUOTE]