Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 10

1) А уровни изоляции зачем придумали ?

2)

обратите внимание на добавленный оператор FOR UPDATE в SELECT. Он блокирует строку, чтобы другие SELECT запросы ждали завершения транзакции. Это позволяет правильно обрабатывать параллельные запросы.

И получить High load и "мы упёрлись в СУБД" на ровном месте .

Сорри, но дальше не стал читать . Потому, что на обсуждение с разрабами темы "вы зачем используете select for update и потом приходите в отдел администрирования баз данных с жалобами "у нас все тормозит" ? ", было потрачено сколько нервов , времени и бесполезных разговоров, что не хочется опять вспоминать.

Стало быть поторопился. Просто уже столько раз натыкался на попытки перенести логику СУБД на уровень приложения , что уже стойкая настороженность возникает.

Ок. Попробую дочитать.

Эх , если бы современные разрабы это читали и руководствовались затем в реальной жизни

Что бы вы ни выбрали, обязательно проводите нагрузочные тесты, чтобы увидеть, как ваш код работает под нагрузкой. Это поможет избежать неприятных сюрпризов в продакшене, когда резко возрастет трафик.

По личному опыту - "неприятные сюрпризы в продакшене" возникают в 100% . Если нагрузка на информационную систему средняя или высокая.

Если внутри fn() вызываемой в теле `runInTx` случится паника то ваш код не вызовет ни коммит ни роллбэк. Думаю безопаснее делать так

func runInTx(db *sql.DB, fn func(tx *sql.Tx) error) (err error) {
	tx, err := db.Begin()
	if err != nil {
		return
	}
	defer func() {
		rollbackErr := tx.Rollback()
		if rollbackErr != nil {
			err = errors.Join(err, rollbackErr)
		}
	}()

	err = fn(tx)
	if err == nil {
		err = tx.Commit()
	}

	return
}

Теперь благодаря деферу роллбэк всегда гарантированно вызывается, просто если это произошло после коммита то ничего не случится, зато если вылетит паника вы корректно откатите начатую транзакцию.

НЛО прилетело и опубликовало эту надпись здесь

Транзакции в слое логики (избегайте, если можете)

...

По мере роста логики вы должны тщательно обдумывать, что должно выполняться внутри транзакции, а что — вне её. Откат повлияет на всё, что вы поместите внутрь функции.

Если в рамках одного запроса от пользователя мне требуется проводить какие-то изменения внутри транзакции, а другие - строго вне, то это повод задуматься о переосмыслении api. Но даже если требуется делать именно так, то ведь на то это и слой логики, что я волен определять, какие действия должны быть атомарными, а какие - нет :)

Не говоря уже о странном аргументе tx, который нужно передавать в методы репозитория.

Что думаете насчёт того, чтобы не заморачиваться и просто создавать (где нужно) отдельную функцию, которая принимает на вход tx? В UpdateByID по сути так и происходит, просто вложено в другую функцию.

Паттерн UpdateFn (наше основное решение)

Принцип "на, держи юзера, измени в нём, что нужно, а я пока покурю" интересен. Но, кажется, что не совсем удобный в более сложных случаях. У вас был опыт применения, когда требуются изменения сразу в нескольких таблицах? Как будто в этом случае часть бизнес логики будет проникать в репозиторий...

похоже на то, непонятно как обрабатывать случаи с изменениями в нескольких агрегатах, как будто распределенная транзакция в монолите, но базовые случаи, на мой взгляд, он покрывает хорошо.

НЛО прилетело и опубликовало эту надпись здесь

По своим наблюдениям считаю, что "Транзакции в слое логики" - оптимальное решение, разве что транзакцию прокинуть в контекст для удобства можно и сделать методы репозитория универсальными (работающими как с tx из контекста так и без него). А tx в контекст прокидывать через метод runInTx. Предлагать целевое решение с оговорками, что оно не для хайлоада, ну... Если не хайлоад, то оптимальнее наверное ORM и не думать.
А в целом я считаю, что если понадобились транзакции, то значит транзакция является неотъемлемой частью бизнес логики и не стоит потеть потаясь её куда-то замести под ковер

НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации