Можно ли получить состояние таблицы с частично обновленными данными при параллельных запросах обновления?
Что проверяют
Понимаете ли вы, где проходит граница атомарности, и умеете ли выразить это в терминах database/sql, а не пересказать наизусть таблицу уровней изоляции.
Как отвечать
Короткий ответ: да, если обновления не собраны в одну транзакцию. Отдельная инструкция обновления атомарна, читатель увидит либо состояние до неё, либо после. Но когда логическая операция это два или три запроса, между ними другой клиент спокойно прочитает половину сделанной работы.
Лечится транзакцией, и в Go важно, каким объектом вы работаете:
tx, err := db.BeginTx(ctx, nil)
if err != nil { return err }
defer tx.Rollback()
// все запросы операции идут через tx, не через db
return tx.Commit()Дальше про уровни. Чтобы не видеть незакоммиченное, хватает уровня по умолчанию. Если внутри одной операции вы делаете несколько чтений и они должны быть согласованы между собой, нужен фиксированный снимок на всю транзакцию. Сериализуемый уровень берут, когда решение о записи принимается по прочитанным данным, и он обязывает повторять транзакцию при ошибке сериализации.
Отдельный случай это потерянное обновление: прочитали значение в память, посчитали, записали обратно. Две горутины затрут работу друг друга. Решения: считать прямо в запросе, брать строку с блокировкой или проверять версию строки в условии обновления.
Где спотыкаются
Открывают транзакцию отдельным запросом через пул. Пул выдаёт соединение на каждый вызов, следующий запрос уедет в другое соединение, и транзакции не получится. Работать нужно через объект транзакции.
Второе: забывают отложенный откат. При раннем возврате по ошибке соединение остаётся занятым, блокировки живут дальше, а пул исчерпывается. Откат после успешной фиксации безопасен, он лишь вернёт признак завершённой транзакции.
Третье: включают строгий уровень изоляции и не пишут повтор. Под нагрузкой запросы начинают падать с ошибкой сериализации, и со стороны это выглядит как отказ базы, хотя это штатный сигнал повторить операцию.