Подробное описание функций пакета database/sql в Go
Categories:
Основные функции управления драйверами
func Drivers() []string
Эта функция возвращает отсортированный список имен зарегистрированных драйверов баз данных.
Пример использования:
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql" // регистрируем MySQL драйвер
_ "github.com/lib/pq" // регистрируем PostgreSQL драйвер
)
func main() {
// Получаем список зарегистрированных драйверов
drivers := sql.Drivers()
fmt.Println("Зарегистрированные драйверы:")
for _, driver := range drivers {
fmt.Println("-", driver)
}
// Выведет что-то вроде:
// Зарегистрированные драйверы:
// - mysql
// - postgres
}
func Register(name string, driver driver.Driver)
Эта функция регистрирует драйвер базы данных под указанным именем. Если попытаться зарегистрировать два драйвера с одинаковым именем или передать nil, функция вызовет panic.
Обычно драйверы регистрируют себя автоматически при импорте с пустым идентификатором _
, как в примере выше. Но можно регистрировать драйверы и вручную:
package main
import (
"database/sql"
"database/sql/driver"
"fmt"
)
// Простой mock-драйвер для примера
type mockDriver struct{}
func (d *mockDriver) Open(name string) (driver.Conn, error) {
fmt.Println("Mock driver открывает соединение с:", name)
return nil, nil
}
func main() {
// Регистрируем наш mock-драйвер
sql.Register("mock", &mockDriver{})
// Теперь можем его использовать
db, err := sql.Open("mock", "test-connection")
if err != nil {
fmt.Println("Ошибка:", err)
return
}
defer db.Close()
// Проверяем, что драйвер зарегистрирован
fmt.Println("Зарегистрированные драйверы:", sql.Drivers())
}
Основные функции для работы с БД
func Open(driverName, dataSourceName string) (*DB, error)
Открывает новое соединение с базой данных. На самом деле не устанавливает соединение сразу, а только готовит объект DB.
Пример:
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
func (*DB) Ping() error
и func (*DB) PingContext(ctx context.Context) error
Проверяет, что соединение с БД живо и доступно.
Пример:
err = db.Ping()
if err != nil {
log.Fatal("Не удалось подключиться к БД:", err)
}
fmt.Println("Успешное подключение к БД!")
Функции выполнения запросов
func (*DB) Exec(query string, args ...interface{}) (Result, error)
func (*DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error)
Выполняет запрос без возврата строк (INSERT, UPDATE, DELETE).
Пример:
result, err := db.Exec(
"INSERT INTO users(name, age) VALUES (?, ?)",
"Alice",
30,
)
if err != nil {
log.Fatal(err)
}
lastID, err := result.LastInsertId()
rowsAffected, err := result.RowsAffected()
func (*DB) Query(query string, args ...interface{}) (*Rows, error)
func (*DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
Выполняет запрос, возвращающий строки (SELECT).
Пример:
rows, err := db.Query("SELECT id, name, age FROM users WHERE age > ?", 25)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var age int
err = rows.Scan(&id, &name, &age)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d: %s, %d\n", id, name, age)
}
if err = rows.Err(); err != nil {
log.Fatal(err)
}
func (*DB) QueryRow(query string, args ...interface{}) *Row
func (*DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row
Выполняет запрос, который должен вернуть не более одной строки.
Пример:
var name string
var age int
err := db.QueryRow("SELECT name, age FROM users WHERE id = ?", 1).Scan(&name, &age)
if err != nil {
if err == sql.ErrNoRows {
fmt.Println("Пользователь не найден")
} else {
log.Fatal(err)
}
} else {
fmt.Printf("Имя: %s, Возраст: %d\n", name, age)
}
Функции для работы с транзакциями
func (*DB) Begin() (*Tx, error)
func (*DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error)
Начинает новую транзакцию.
Пример:
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
// Откатываем транзакцию в случае ошибки
defer func() {
if err != nil {
tx.Rollback()
}
}()
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
if err != nil {
return err
}
_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
if err != nil {
return err
}
// Если все успешно - коммитим
err = tx.Commit()
if err != nil {
return err
}
Работа с соединениями
func (*DB) Conn(ctx context.Context) (*Conn, error)
Получает одно соединение из пула для выполнения нескольких операций в одном контексте.
Пример:
conn, err := db.Conn(context.Background())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// Выполняем несколько операций в одном соединении
var count int
err = conn.QueryRowContext(context.Background(), "SELECT COUNT(*) FROM users").Scan(&count)
if err != nil {
log.Fatal(err)
}
_, err = conn.ExecContext(context.Background(), "UPDATE stats SET user_count = ?", count)
if err != nil {
log.Fatal(err)
}
Заключение
Пакет database/sql
предоставляет все необходимые функции для работы с SQL-базами данных в Go. Основные принципы:
- Всегда проверяйте ошибки
- Закрывайте ресурсы (Rows, Tx, Conn) с помощью defer
- Используйте контексты для управления таймаутами
- Для разных типов запросов используйте соответствующие методы (Exec, Query, QueryRow)
Правильное использование этих функций позволит вам создавать надежные и эффективные приложения, работающие с базами данных.