Многие, покупая новую машину, не знают как в ней свет включается. А элементы управления кажутся такими неудобными, после старой машины. Но уже через месяц езды понимают, что все очень удобно и практично. Дело привычки.
Я, кстати, так и не понял, чем вас не устраивает стандартная конструкция lock () {}, что вы реализовали свою? Кроме lock() в .Net есть еще несколько средств для синхронизации потоков, на любой вкус, так сказать. Да и вызывать .Lock в одном методе, а освобождать ресурс в другом не очень красиво :-) Посмотрите как можно использовать IDisposable в связке с using для неявного освобождения ресурсов. И ваш CurrentThreadLocks может обрести человеческое лицо несмотря на то, что он наверняка дублирует уже существующий класс.
«Заведем табличку CurrentThreadLocks» — и будем мучаться с кодом для синхронизации еще и этой таблички :-)
Я рассматриваю свой пример в контексте своего кода, а не вашего. В моем случае, на всю библиотеку нет ни одной явной транзакции. Т.е. в коде удалось избежать использования транзакций.
TABLOCKX не блокирует таблицу на время транзакции. Только на время выполнения одной инструкции. Поэтому новые записи будут видны другим транзакциям. Я не ручаюсь за все сказанное на 100%, поскольку я не обладаю познаниями DBA в SQL Server, но у меня все прекрасно работает в таком виде.
А я как-раз не вижу тривиального способа реализовать CurrentThreadLocker в условиях, когда код запускается на нескольких машинах, разбросанных по интернету :-)
Нет, показанный в примере запрос это запрос вида INSERT FROM SELECT
т.е. мы вставляем то, что нашли. SQL так хитро устроен, что не всегда все происходит в таком порядке, как написано :-)
В моем примере, если записи еще нет, то мы выберем строку данных, построив ее из входящих параметров, и ее же вставим в таблицу. Если запись есть, то SELECT вернет «пустой результат» и вставлять будет нечего.
TABLOCKX это блокировка таблицы на время выполнения одной инструкции с этой таблицей (тут я могу быть не точным — специально в мануал сейчас не смотрел). Т.е. другие такие же запросы будут ждать пока не отработает этот. И никаких явных транзакций!
Как я уже писал, это как-минимум поможет сделать ваш код масштабируемым. Но, если вам точно не нужно будет в будущем запускать этот код на больше чем одной машине одновременно — то тогда лучше все блокировки реализовывать исключительно в коде. Хотя везде есть свои ньюансы.
Недавно я решал похожую задачу, но для SQl Server.
Вообще-то, стоит отметить, что решение такой задачи с помощью блокировок на уровне кода делает такое решение не масштабируемым.
Именно поэтому я остановился на варианте выполнения проверки и вставки новой записи на уровне БД.
Примерно так:
INSERT INTO T WITH (TABLOCKX)
([To], [From], Name, ...)
SELECT @To, @From, Name,…
WHERE NOT EXISTS (SELECT * FROM T WHERE Name = @Name ...)
Ключевой момент здесь — WITH (TABLOCKX)
Но этот вариант хорош тогда, когда выборку и вставку можно сделать одним запросом.
Теперь понятно, спасибо за ссылку на оригинальную презентацию.
Вообще-то идея сообщать о том, что паддинг неверный зря пришла в голову разработчикам, в любом случае. Это как в ответ на попытку расшифровать данные говорить о том, что столько-то бит ключа из 128 (например) неверные :-)
Ну IMHO для случая, когда надо выбрать/записать данные в 1-2-3 таблицы LINQ 2 SQL предпочительнее.
В том виде, в котором существует LINQ 2 SQL, его достаточно для большинства простых задач. Собственно, видимо поэтому его больше и не развивают. И не надо :-)
Автору перевода спасибо. Лично мне стилистика понравилась. Надеюсь, у источника было так же :-)
Комментаторам, пожалуйста, не надо писать о синтаксических, грамматических, стилистических и других ошибках в комментариях к статье. Для этого есть личная почта. А так получается половина комментариев «ни о чем».
«Заведем табличку CurrentThreadLocks» — и будем мучаться с кодом для синхронизации еще и этой таблички :-)
т.е. мы вставляем то, что нашли. SQL так хитро устроен, что не всегда все происходит в таком порядке, как написано :-)
В моем примере, если записи еще нет, то мы выберем строку данных, построив ее из входящих параметров, и ее же вставим в таблицу. Если запись есть, то SELECT вернет «пустой результат» и вставлять будет нечего.
TABLOCKX это блокировка таблицы на время выполнения одной инструкции с этой таблицей (тут я могу быть не точным — специально в мануал сейчас не смотрел). Т.е. другие такие же запросы будут ждать пока не отработает этот. И никаких явных транзакций!
Вообще-то, стоит отметить, что решение такой задачи с помощью блокировок на уровне кода делает такое решение не масштабируемым.
Именно поэтому я остановился на варианте выполнения проверки и вставки новой записи на уровне БД.
Примерно так:
INSERT INTO T WITH (TABLOCKX)
([To], [From], Name, ...)
SELECT @To, @From, Name,…
WHERE NOT EXISTS (SELECT * FROM T WHERE Name = @Name ...)
Ключевой момент здесь — WITH (TABLOCKX)
Но этот вариант хорош тогда, когда выборку и вставку можно сделать одним запросом.
Вообще-то идея сообщать о том, что паддинг неверный зря пришла в голову разработчикам, в любом случае. Это как в ответ на попытку расшифровать данные говорить о том, что столько-то бит ключа из 128 (например) неверные :-)
В том виде, в котором существует LINQ 2 SQL, его достаточно для большинства простых задач. Собственно, видимо поэтому его больше и не развивают. И не надо :-)
Комментаторам, пожалуйста, не надо писать о синтаксических, грамматических, стилистических и других ошибках в комментариях к статье. Для этого есть личная почта. А так получается половина комментариев «ни о чем».