среда, 1 сентября 2021 г.

Открытие дескриптора базы данных с Golang

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

Другими словами, это дескриптор базы данных, представленный sql.DB, обрабатывает соединения, открывая и закрывая их от имени вашего кода. Поскольку ваш код использует дескриптор для выполнения операций с базой данных, эти операции имеют конкурентный доступ к базе данных.

В дополнение к API, доступным в пакете database/sql, сообщество Go разработало драйверы для всех наиболее распространенных (и многих необычных) систем управления базами данных (СУБД).

При открытии дескриптора базы данных вы выполняете следующие высокоуровневые шаги:

  1. Находите драйвер.
    Драйвер переводит запросы и ответы между вашим кодом Go и базой данных.
  2. Открываете дескриптор базы данных.
    После того, как вы импортировали драйвер, вы можете открыть дескриптор конкретной базы данных.
  3. Подтверждаете соединение.
    После того, как вы открыли дескриптор базы данных, ваш код может проверить, доступно ли соединение.

Ваш код обычно не открывает и не закрывает соединения с базой данных явно - это делается дескриптором базы данных. Однако ваш код должен освобождать ресурсы, которые он получает в процессе, например sql.Rows, содержащий результаты запроса.

Поиск и импорт драйвера базы данных

Вам понадобится драйвер базы данных, поддерживающий СУБД, которую вы используете. Чтобы найти драйвер для своей базы данных, см. SQLDrivers.

Чтобы сделать драйвер доступным для вашего кода, вы импортируете его, как любой другой пакет Go. Например:

import "github.com/go-sql-driver/mysql"

Обратите внимание, что если вы не вызываете какие-либо функции непосредственно из пакета драйвера - например, когда он неявно используется пакетом sql - вам нужно будет использовать пустой импорт с префиксом пути импорта с подчеркиванием:

import _ "github.com/go-sql-driver/mysql"

Примечание. Рекомендуется избегать использования собственного API драйвера базы данных для операций с базой данных. Вместо этого используйте функции из пакета database/sql. Это поможет сохранить слабую связанность вашего кода с СУБД, облегчая при необходимости переключение на другую СУБД.

Открытие дескриптора базы данных

Дескриптор базы данных sql.DB обеспечивает возможность чтения и записи в базу данных по отдельности или в транзакции.

Вы можете получить дескриптор базы данных, вызвав либо sql.Open (который принимает строку подключения), либо sql.OpenDB (который принимает driver.Connector). Оба возвращают указатель на sql.DB.

Примечание. Убедитесь, что учетные данные вашей базы данных не попали в исходный Go код.

Открытие с помощью строки подключения

Используйте функцию sql.Open, если вы хотите подключиться с помощью строки подключения. Формат строки зависит от используемого драйвера.

Вот пример для MySQL:

db, err = sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/jazzrecords")
if err != nil {
    log.Fatal(err)
}

Однако вы, вероятно, обнаружите, что более структурированный сбор параметров соединения дает вам более читаемый код. Подробности зависят от драйвера.

Например, вы можете заменить предыдущий пример следующим, в котором используется конфигурация драйвера MySQL для указания параметров и его метод FormatDSN для построения строки подключения.

// Указываем параметры подключения.
cfg := mysql.Config{
    User:   username,
    Passwd: password,
    Net:    "tcp",
    Addr:   "127.0.0.1:3306",
    DBName: "jazzrecords",
}

// Получаем дескриптор базы данных.
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
    log.Fatal(err)
}

Открытие с помощью коннектора

Используйте функцию sql.OpenDB, если вы хотите воспользоваться специфичными для драйвера функциями подключения, которые недоступны в строке подключения. Каждый драйвер поддерживает свой собственный набор параметров подключения, часто предоставляя способы настройки запроса подключения, специфичного для СУБД.

Адаптировав предыдущий пример sql.Open для использования sql.OpenDB, вы можете создать дескриптор с таким кодом, как следующий:

// Указываем параметры подключения.
cfg := mysql.Config{
    User:   username,
    Passwd: password,
    Net:    "tcp",
    Addr:   "127.0.0.1:3306",
    DBName: "jazzrecords",
}

// Получаем коннектор для конкретного драйвера.
connector, err := mysql.NewConnector(&cfg)
if err != nil {
    log.Fatal(err)
}

// Получаем дескриптор базы данных.
db = sql.OpenDB(connector)

Обработка ошибок

Ваш код должен проверять наличие ошибки при попытке создать дескриптор, например, с sql.Open. Это не будет ошибкой подключения. Вместо этого вы получите сообщение об ошибке, если sql.Open не удалось инициализировать дескриптор. Это может произойти, например, если он не может проанализировать указанный вами DSN.

Подтверждение подключения

Когда вы открываете дескриптор базы данных, пакет sql может не сразу создать новое соединение с базой данных. Вместо этого он может создать соединение, когда это необходимо вашему коду. Если вы не собираетесь использовать базу данных сразу и хотите подтвердить, что соединение может быть установлено, вызовите Ping или PingContext.

Код в следующем примере проверяет базу данных, чтобы подтвердить соединение.

db, err = sql.Open("mysql", connString)

// Подтверждаем успешное соединение.
if err := db.Ping(); err != nil {
    log.Fatal(err)
}

Хранение учетных данных базы данных

Избегайте хранения учетных данных базы данных в исходном Go коде, так как это может открыть доступ к содержимому вашей базы данных другим пользователям. Вместо этого найдите способ хранить их за пределами вашего кода, но доступными для него. Например, рассмотрим приложение-хранитель секретов, которое хранит учетные данные и предоставляет API, который ваш код может использовать для получения учетных данных для аутентификации в вашей СУБД.

Один из популярных подходов - хранить секреты в среде до запуска программы, возможно, загруженные из секретного менеджера, а затем ваша Go программа может прочитать их с помощью os.Getenv:

username := os.Getenv("DB_USER")
password := os.Getenv("DB_PASS")

Этот подход также позволяет вам самостоятельно устанавливать переменные среды для локального тестирования.

Освобождение ресурсов

Хотя вы не управляете и не закрываете соединения явно с помощью пакета database/sql, ваш код должен освобождать ресурсы, которые он получил, когда они больше не нужны. Они могут включать ресурсы, удерживаемые sql.Rows, представляющие данные, возвращенные из запроса, или sql.Stmt, представляющие подготовленный оператор.

Обычно вы закрываете ресурсы, откладывая вызов функции Close, чтобы ресурсы высвобождались до выхода из включающей функции.

Код в следующем примере откладывает Close, чтобы освободить ресурс, удерживаемый sql.Rows.

rows, err := db.Query("SELECT * FROM album WHERE artist = ?", artist)
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

// Цикл по возвращенным rows.


Читайте также:


Купить gopher

Комментариев нет:

Отправить комментарий