Александр Гольцман
Разбираемся с SQL в Golang
Работа с базами данных — ключевая часть бэкенд-разработки. В языке программирования Go (или Golang) для взаимодействия с реляционными базами данных используется стандартная библиотека database/sql
, а также сторонние ORM и библиотеки для удобной работы с SQL-запросами.
В этой статье я покажу, как подключаться к базе данных, выполнять SQL-запросы и разберу популярные инструменты для работы с SQL в Go. Вы узнаете, как работать с транзакциями, подготовленными запросами и как выбрать оптимальный подход в зависимости от требований проекта.
Библиотека database/sql
и драйверы
Go предоставляет стандартный интерфейс для работы с базами данных через пакет database/sql
. Однако он не включает в себя реализацию для конкретных СУБД (PostgreSQL, MySQL, SQLite и других), поэтому для работы с конкретной базой необходимо подключать соответствующий драйвер.
Примеры популярных драйверов:
- PostgreSQL –
github.com/lib/pq
- MySQL –
github.com/go-sql-driver/mysql
- SQLite –
github.com/mattn/go-sqlite3
Драйверы реализуют интерфейс database/sql
, что позволяет работать с разными базами данных схожим образом.
Подключение к базе данных
Подключение к базе выполняется через sql.Open()
. Смотрите, как можно подключиться к PostgreSQL:
import (
"database/sql"
_ "github.com/lib/pq"
)
func main() {
connStr := "user=username dbname=mydb sslmode=disable"
db, err := sql.Open("postgres", connStr)
if err != nil {
panic(err)
}
defer db.Close()
}
Обратите внимание, что sql.Open()
не устанавливает реальное соединение, а только создает объект базы данных. Чтобы проверить подключение, используйте db.Ping()
.
if err := db.Ping(); err != nil {
log.Fatal("Не удалось подключиться к базе данных:", err)
}
Это особенно важно для определения ошибок аутентификации или проблем с сетью.
Выполнение SQL-запросов
Для выполнения SQL-запросов используются методы:
Exec()
– для запросов без результата (INSERT, UPDATE, DELETE).Query()
– для получения множества строк.QueryRow()
– для запроса одной строки.
Вот пример вставки данных в таблицу:
_, err := db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", "Alice", 30)
if err != nil {
log.Fatal(err)
}
А теперь посмотрим, как извлекать данные:
rows, err := db.Query("SELECT id, name, age FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
var age int
if err := rows.Scan(&id, &name, &age); err != nil {
log.Fatal(err)
}
fmt.Println(id, name, age)
}
Метод rows.Scan()
считывает данные из результата запроса.
Подготовленные запросы
Использование подготовленных запросов (Prepared Statements
) позволяет повысить безопасность и производительность.
stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES ($1, $2)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
_, err = stmt.Exec("Bob", 25)
if err != nil {
log.Fatal(err)
}
База данных кэширует запрос, что ускоряет повторное выполнение.
Транзакции в Go
Транзакции позволяют выполнять несколько операций как единое целое. Если одна из них завершится с ошибкой, все изменения откатятся (Rollback()
), иначе — зафиксируются (Commit()
).
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE id = $1", 1)
if err != nil {
tx.Rollback()
log.Fatal(err)
}
_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE id = $1", 2)
if err != nil {
tx.Rollback()
log.Fatal(err)
}
err = tx.Commit()
if err != nil {
log.Fatal(err)
}
Это полезно для финансовых операций и других критичных процессов.
Использование ORM: gorm
Если писать SQL-запросы вручную неудобно, можно использовать ORM-библиотеки. Самая популярная ORM в Go — gorm (gorm.io/gorm
). Она позволяет работать с базой через структуры.
Пример использования gorm
:
type User struct {
ID uint
Name string
Age int
}
db.Create(&User{Name: "Charlie", Age: 28})
Go сам формирует SQL-запрос, что упрощает работу с базой данных.
Когда использовать database/sql
, а когда gorm
?
Каждый подход имеет свои преимущества:
database/sql
подходит для высоконагруженных систем, где важен полный контроль над SQL-запросами. Он минималистичен и не добавляет лишних абстракций.gorm
удобен для быстрого прототипирования и проектов, где работа с данными похожа на объектно-ориентированное программирование. Однако он менее эффективен при сложных SQL-запросах.
Выбор зависит от требований вашего проекта.
Заключение
В Go можно работать с базами данных разными способами: через стандартную библиотеку database/sql
или используя ORM-библиотеки.
Если вам нужен максимальный контроль и производительность, database/sql
— лучший вариант. Но если важнее удобство и скорость разработки, стоит присмотреться к gorm
.
Смотрите, что важно учитывать при выборе: если ваш проект предполагает сложные SQL-запросы и высокую нагрузку, database/sql
обеспечит большую гибкость. Если же вам нужно быстро разрабатывать API с базой данных, ORM-библиотеки, такие как gorm
, помогут сократить объем кода.
Независимо от выбранного подхода, стоит учитывать безопасность (использовать подготовленные запросы), следить за соединениями с базой данных и эффективно управлять транзакциями.
Карта развития разработчика
Получите полную карту развития разработчика по всем направлениям: frontend, backend, devops, mobile