layout | title |
---|---|
article |
Изменение данных и работа с транзакциями |
Теперь мы готовы рассмотреть, как изменять данные и работать с транзакциями. Различие может показаться искусственным, если вы привыкли к языкам программирования, использующим объект "выражение" для получения строк и изменения данных, но в Go существует важная причина для этого различия.
Используйте Exec()
, желательно с подготовленным выражением, чтобы выполнить операцию INSERT
, UPDATE
, DELETE
или другое выражение, которое не возвращает строки. В следующем примере показано, как вставить строку и проверить метаданные о данной операции:
stmt, err := db.Prepare("INSERT INTO users(name) VALUES(?)")
if err != nil {
log.Fatal(err)
}
res, err := stmt.Exec("Долли")
if err != nil {
log.Fatal(err)
}
lastId, err := res.LastInsertId()
if err != nil {
log.Fatal(err)
}
rowCnt, err := res.RowsAffected()
if err != nil {
log.Fatal(err)
}
log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)
Выполнение выражения производит sql.Result
, который предоставляет доступ к метаданным выражения: последнему вставленному ID и количеству затронутых строк.
А что делать, если вам не важно результат? А что делать, если вы просто хотите выполнить выражение и проверить наличие ошибок, игнорируя результат? Не будут ли следующие два выражения выполнять одно и то же?
_, err := db.Exec("DELETE FROM users") // ОК
_, err := db.Query("DELETE FROM users") // НЕПРАВИЛЬНО
Ответ — нет. Они не делают одно и то же, и вы никогда не должны использовать Query()
таким образом. Выражение Query()
вернет sql.Rows
, которое зарезервирует соединение с базой данных до тех пор, пока sql.Rows
не будет закрыто.
Существует возможность непрочитанных данных (например, больше строк), поэтому соединение не может использоваться. В данном примере соединение никогда не будет освобождено снова. Утилита сборщика мусора в конечном итоге закроет основной net.Conn
за вас, но это может занять длительное время. Кроме того, пакет database/sql
продолжает отслеживать соединение в пуле, надеясь, что вы его освободите в какой-то момент, чтобы соединение могло быть использовано снова.
Эта антипаттерн является хорошим способом исчерпания ресурсов (например, слишком много соединений).
В Go транзакция представляет собой объект, который зарезервирует соединение с хранилищем данных. Она позволяет выполнять все операции, которые мы видели ранее, гарантируя, что они будут выполняться на одном и том же соединении.
Вы начинаете транзакцию вызовом db.Begin()
, а завершаете её методами Commit()
или Rollback()
на полученном объекте Tx
. Под капотом Tx
получает соединение из пула и зарезервирует его только для использования этой транзакции. Методы на Tx
один-к-одному соответствуют методам, которые можно вызвать напрямую на базе данных, таких как Query()
и так далее.
Подготовленные выражения, созданные в рамках транзакции, привязываются исключительно к этой транзакции. Смотрите подготовленные выражения для более подробной информации.
Не следует смешивать использование функций, связанных с транзакциями, таких как Begin()
и Commit()
, с SQL выражениями, такими как BEGIN
и COMMIT
в вашем SQL коде. Это может привести к плохим последствиям:
Tx
могут остаться открытыми, зарезервировав соединение из пула и не вернув его обратно.Пока вы работаете внутри транзакции, следует быть внимательным и не делать вызовы к переменной Db
. Делайте все свои вызовы к переменной Tx
, созданной с помощью db.Begin()
. Переменная Db
не находится в транзакции, только Tx
находится в ней. Если вы сделаете дальнейшие вызовы к db.Exec()
или аналогичным методам, эти вызовы произойдут вне области вашего транзакционного контекста, на других соединениях.
Если вам требуется работать с несколькими выражениями, изменяющими состояние соединения, вам потребуется Tx
, даже если вы не хотите иметь конкретную транзакцию. Например:
SET @var := somevalue
в MySQL.Если вам требуется выполнить любое из этих действий, вам потребуется привязать свою активность к единственному соединению, и единственный способ сделать это в Go — использовать Tx
.
Предыдущий: Извлечение множества результатов Следующий: Использование подготовленных выражений
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )