Редактировать: Мое понимание в этом ответе неверно, я просто оставляю его для документации на случай, если я когда-нибудь захочу вернуться к нему.
После некоторого расследования я считаю, что это будет работать как задумано.
Причина в том, что для этого вызова:
MyModel.objects.select_for_update().order_by('id').last().id
SQL Django генерирует и работает с БД на самом деле:
SELECT ... FROM MyModel ORDER BY id ASC FOR UPDATE;
(вызов только last()
происходит после того, как набор запросов уже оценен.)
Это означает, что запрос просматривает все строки при каждом запуске.Это означает, что во второй раз он подберет новую строку и вернет ее соответственно.
Я узнал, что это явление называется «фантомным чтением» и возможно, потому что уровень изоляции моего БД равен REPEATABLE-READ
.
@ KevinChristopherHenry "Проблема в том, чтозапрос не повторяется после снятия блокировки, строки уже выбраны "Вы уверены, что так оно и есть?Почему READ COMMITTED подразумевает, что выбор не запускается после снятия блокировки?Я думал, что уровень изоляции определяет, какой снимок данных видит запрос, когда он выполняется, а не ~ когда запрос выполняется.Мне кажется, что выбор происходит до или после снятия блокировки, ортогонально уровню изоляции.И по определению, заблокированный запрос не выбирает строки до тех пор, пока он не будет разблокирован?
Для чего я пытался проверить это, открыв два отдельных соединения с моим БД в оболочке и выполнив некоторыезапросы.Во-первых, я начал транзакцию и получил блокировку «select * from MyModel order by id для обновления».Затем, во втором, я сделал то же самое, заставив select заблокироватьЗатем вернувшись в первую очередь, я вставил новую строку и подтвердил транзакцию.Затем во втором запрос разблокируется, и возвращается новая строка.Это заставляет меня думать, что моя гипотеза верна.
PS Наконец-то я прочитал документацию «нежелательных результатов», которую вы прочитали, и я понял вашу точку зрения - в этом примере похоже, что он игнорирует строки, которые не были предварительно выбраны, так что это может указывать на вывод, что мой второй запрос не подхватит новую строку.Но я проверил в оболочке, и это сделал.Теперь я не знаю, что с этим делать.