1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/dana-go-database-sql-tutorial-translation

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
11.0.surprises.md 9.5 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 02.03.2025 18:11 571ab8e
layout title
article
Неожиданности, Антипаттерны и Ограничения

Хотя database/sql прост после того как вы привыкнете к нему, вы можете удивиться сложностью некоторых сценариев использования, которые он поддерживает. Это характерно для основных библиотек Go.

Иногда использование ресурсов может вызвать проблемы:

Утомление ресурсами

Как упоминалось на этом сайте, если вы не используете database/sql в соответствии с его предназначением, вы можете создать себе проблемы, обычно связанные с использованием или недопустимым использованием ресурсов:

  • Открытие и закрытие баз данных могут привести к утомлению ресурсов.
  • Недочтение всех строк или отсутствие вызова rows.Close() заблокирует соединения из пула.
  • Использование Query() для запроса, который не возвращает строки, будет забирать соединение из пула.
  • Незнание того, как работают подготовленные запросы, может привести к увеличенному количеству действий в базе данных.

Большые значения типа uint64

Здесь представлено неожиданное сообщение об ошибке. Вы не сможете передать большие целые числа типа uint64, если старший бит установлен:

_, err := db.Exec("INSERT INTO users(id) VALUES", math.MaxUint64)

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

Расхождение состояния соединения

Некоторые вещи могут менять состояние соединения, что может вызвать проблемы по двум причинам:

  1. Некоторое состояние соединения, такое как наличие транзакции, должно управляться через типы Go.
  2. Вы можете считать, что ваши запросы выполняются на одном соединении, когда это не так.

Например, установка текущей базы данных с помощью команды USE является обычной практикой для многих людей. Однако в Go это затронет только соединение, которое вы используете. Если вы не в транзакции, другие заявки, которые вы полагаете выполнены на этом соединении, могут фактически выполняться на других соединениях из пула, поэтому они не будут видеть эффекты таких изменений.

Кроме того, после изменения соединения, оно вернется в пул и потенциально "запятнает" состояние для некоторого другого кода. Это одна из причин, почему вы никогда не должны выполнять команды BEGIN или COMMIT напрямую как SQL-запросы.

Специфическая синтаксис баз данных

API database/sql предоставляет абстракцию ориентированной на строки базы данных, но конкретные базы данных и драйверы могут различаться по поведению и/или синтаксису, таким образом как место заполнения подготовленных запросов.

Поддержка нескольких наборов результатов

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

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

Вызов хранимых процедур

Вызов хранимых процедур зависит от драйвера, но в драйвере MySQL это невозможно в настоящее время. Может показаться, что вы сможете вызвать простую процедуру, которая возвращает один набор результатов, выполняя что-то вроде этого:

err := db.QueryRow("CALL mydb.myprocedure").Scan(&result)

На самом деле, это не будет работать. Вы получите следующее сообщение об ошибке: Ошибка 1312: Процедура mydb.myprocedure не может вернуть набор результатов в данном контексте. Это потому, что MySQL ожидает, чтобы соединение было установлено в режим многокомандного выполнения, даже для одного набора результатов, а драйвер не делает этого в настоящий момент (хотя см. эту задачу).

Поддержка множественных команд

database/sql не имеет явной поддержки множественных команд, что означает, что поведение этого зависит от сервера:

_, err := db.Exec("DELETE FROM tbl1; DELETE FROM tbl2")

Сервер имеет право интерпретировать это любым образом, что может включать возвращение ошибки, выполнение только первой команды или выполнение обеих.

Аналогично, нет возможности группировать команды в транзакции. Каждая команда в транзакции должна быть выполнена последовательно, и ресурсы в результате, такие как Row или Rows, должны быть сканированы или закрыты, чтобы освободить подлежащее соединение для следующей команды. Это отличается от обычного поведения, когда вы работаете без транзакции. В этой ситуации вполне возможно выполнить запрос, пройтись по строкам и внутри цикла выполнить запрос к базе данных (что произойдет на новом соединении):

rows, err := db.Query("select * from tbl1") // Использует соединение 1
for rows.Next() {
	err = rows.Scan(&myvariable)
	// СЛЕДУЮЩЕЕ ЗАПРОСИТЕЛЬСТВО НЕ ИСПОЛЬЗУЕТ СОЕДИНЕНИЕ 1, которое уже используется
	db.Query("select * from tbl2 where id = ?", myvariable)
}

Но транзакции ограничиваются одним соединением, поэтому это невозможно с транзакциями:

tx, err := db.Begin()
rows, err := tx.Query("select * from tbl1") // Использует соединение tx
for rows.Next() {
	err = rows.Scan(&myvariable)
	// ОШИБКА! Соединение tx занято!
	tx.Query("select * from tbl2 where id = ?", myvariable)
}

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

Предыдущий: Пул соединений Следующий: Связанные материалы и ресурсы

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/dana-go-database-sql-tutorial-translation.git
git@api.gitlife.ru:oschina-mirror/dana-go-database-sql-tutorial-translation.git
oschina-mirror
dana-go-database-sql-tutorial-translation
dana-go-database-sql-tutorial-translation
master