Ответ на сообщение
Коллеги, что вы думаете о данном коде?
Цитата:
Сообщение от
MikeR
Вторая ссылка тоже ни о чем не говорит?
Значит вы не поняли или не смог я вам объяснить.
Если бы вы внимательно прочитали ссылку, которую привели, то увидели бы, что там есть анонс описания механизма OCC, который описан буквально в следующей статье
Излучая оптимизм и доступен уже начина с KR2 для трешки (а для четверки и следующих версий доступен уже с начальной версии).
Так вот, с включенным оптимистическим OCC никакой блокировки при вызове [while] select forUpdate уже не происходит (вот насчет того, что блокировка отключается и в трешке не уверен

).
Да и приведенный в статье код - это попытка задействовать этот самый механизм при отсутствии его поддержки ядром
Правда, с моей точки зрения, в данном конкретном случае никаких преимуществ это не дает.
- судя по изначальному алгоритму, должны быть изменены все записи, попадающие в выборку. А это автоматически влечет за собой блокировку, независимо от включенного режима конкуренции
- время, которое удерживаются блокировки, в варианте исправления только увеличится, что приведет к увеличению вероятности возникновения взаимоблокировок
- фраза "while select forupdate, который можеn привести к блокировке таблицы" актуальна только при большом количестве записей в выборке (>5000), причем, эскалация произойдет не сразу. Да и для отдельной выборки эскалация все равно может произойти в случае превышения выделенной под блокировки памяти (для всех соединений, а не только текущего)
- сам вариант исправления не совсем корректен к изначальному алгоритму (и к механизму OCC) - в изначальной выборке может быть больше записей, чем было затем обработано
И, если уж идет речь об исключении эскалации, то более эффективно будет управлять этим на уровне настроек SQL-сервера, а не прикладного кода.
Хотя, есть маленький финт, который позволит блокировать эскалации из алгоритма, в случае если надо обработать много записей.
Достаточно перед выполнением
while select forUpdate сделать запрос с блокировкой к несуществующей записи в отдельном коннекте в своем контексте транзакции, которая будет удерживаться все время выполнения операции
X++:
MyTable myTableLock;
MyTable myTable;
UserConnection uc = new UserConnection();
;
myTableLock.setConnection(uc);
myTableLock.concurrencyModel(ConcurrencyModel::Pessimistic); // Это нужно для 2009-й (и четверки, по всей видимости) для гарантированного срабатывания
uc.ttsbegin();
select forUpdate myTableLock
where myTableLock.RecId == 0;
//Дальше можно выполнять обработку большего количества записей таблицы
ttsbegin;
myTable.concurrencyModel(ConcurrencyModel::Pessimistic); // Это нужно для 2009-й (и четверки, по всей видимости) для гарантированного срабатывания
while select forUpdate myTable
{
myTable.update();
}
ttscommit;
uc.ttsabort();
На время удержания транзакции в доп. соединении эскалация будет исключена полностью для таблицы для любого соединения, в том числе и по причине исчерпания памяти, так что надо использовать с осторожностью, если возникнет необходимость
С включенной оптимистической конкуренцией этот хинт, естественно, не нужен