Статьи
Управление данными

Как упростить работу с базами данных в Golang с SQLX

Golang с SQLX
SQLX — удобная широкофункциональная библиотека для упрощения операций над базами данных. В ее основе — стандартный пакет Go database/sql.


Выполним с ней некоторые операции в MySQL.

Установка

Сначала устанавливаем пакет sqlx, драйверы sql и mysql:
go get github.com/jmoiron/sqlx
go get -u github.com/go-sql-driver/mysql
Теперь импортируем эти пакеты, причем mysql с подчеркиванием — его мы используем косвенно:
import (
  _ "github.com/go-sql-driver/mysql"
  "github.com/jmoiron/sqlx"
)

Подключение

// Строка подключения к базе данных
 dsn := "user:password@(localhost:3306)/database_name"

 // Инициализируем подключение к базе данных
 db, err := sqlx.Connect("mysql", dsn)
 if err != nil {
  panic("Failed to connect to the database: " + err.Error())
 }

 // Проверяем, что подключение к БД еще рабочее
 err = db.Ping()
 if err != nil {
  panic("Failed to ping the database: " + err.Error())
 }
В этом коде мы открыли подключение к MySQL, затем проверили, нет ли ошибки подключения и сбоев в работе.

Совместимость с базами данных

В примере ниже драйвер MySQL можно легко поменять, установите свой драйвер и поменяйте параметр драйвера sql в функции connect:
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
// Драйвер MySQL
import _ "github.com/go-sql-driver/mysql"

// Драйвер PostgreSQL
import _ "github.com/lib/pq"

Автоматическое сканирование структуры

Со стандартным пакетом приходится определять все переменные и извлекать их в цикле for:
rows, err := db.Query("SELECT id, name, price FROM products")
 if err != nil {
  // Обработка ошибок
 }

 for rows.Next() {
  var id int
  var name string
  var price float64
  err = rows.Scan(&id, &name, &price)
  if err != nil {
   // Обработка ошибок
  }
  
  fmt.Println(id, name, price)
 }
С SQLX все проще, возвращаемый из базы данных результат отправляется прямиком в структуру:
type Product struct {
 ID    int     `db:"id"`
 Name  string  `db:"name"`
 Price float64 `db:"price"`
}


 var products []Product
 // Из базы данных извлекаются все продукты
 err = db.Select(&products, "SELECT id, name, price FROM products")
 if err != nil {
  // Обработка ошибок
 }
 fmt.Println(products)
Если нужно получить всего одну строку, применяем функцию Get:
var product Product
 // Из базы данных извлекается только одна строка
 err = db.Get(&product, "SELECT id, name, price FROM products where id = 1")
 if err != nil {
  // Обработка ошибок
 }
 fmt.Println(product)
С помощью структур вставляются новые строки:
// Создаем новый продукт
 var product Product = Product{
  Name:  "New Product",
  Price: 350,
 }

 // Используя сканирование структуры, вставляем его в таблицу продуктов
 response, err := db.NamedExec("INSERT INTO products (name, price) VALUES (:name, :price)", &product)
 if err != nil {
  // Обработка ошибок
 }

 // Получаем последний вставленный идентификатор
 lastId, err := response.LastInsertId()
 if err != nil {
  // Обработка ошибок
 }

 // Получаем число соответствующих строк
 affectedRow, err := response.RowsAffected()
 if err != nil {
  // Обработка ошибок
 }

 fmt.Println(lastId, affectedRow)

Привязка параметров в целях безопасности

Привязкой параметров в SQLX предотвращаются SQL-инъекции:
var product Product
 // Привязываем параметр идентификатора
 err = db.Get(&product, "SELECT id, name, price FROM products where id = ?", 1)
 if err != nil {
  // Обработка ошибок
 }
 fmt.Println(product)
Подробнее — в документации.