Работа с базами данных

9. Работа с базами данных #

Работа с базами данных в Go включает взаимодействие через стандартный пакет database/sql и использование ORM для упрощения операций. Go также поддерживает интеграцию с NoSQL-решениями.


9.1 Введение в database/sql #

Пакет database/sql предоставляет интерфейс для работы с реляционными базами данных (MySQL, PostgreSQL, SQLite и др.). Для подключения к базе данных используются драйверы, такие как github.com/lib/pq для PostgreSQL или github.com/go-sql-driver/mysql для MySQL.

Пример подключения к базе данных и выполнения запросов:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq" // Драйвер PostgreSQL
)

func main() {
    connStr := "user=postgres password=secret dbname=mydb sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // Выполнение запроса
    rows, err := db.Query("SELECT id, name FROM users")
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    for rows.Next() {
        var id int
        var name string
        err := rows.Scan(&id, &name)
        if err != nil {
            panic(err)
        }
        fmt.Printf("ID: %d, Name: %s\n", id, name)
    }
}

9.2 Использование ORM (GORM, Ent) #

GORM #

GORM (gorm.io/gorm) — это популярный ORM для Go, предоставляющий высокоуровневый интерфейс для работы с базой данных.

Пример работы с GORM:

package main

import (
    "fmt"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type User struct {
    ID   uint
    Name string
    Age  int
}

func main() {
    dsn := "user=postgres password=secret dbname=mydb sslmode=disable"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    // Миграция схемы
    db.AutoMigrate(&User{})

    // Создание записи
    db.Create(&User{Name: "Иван", Age: 30})

    // Чтение записи
    var user User
    db.First(&user, 1) // Найти пользователя с ID=1
    fmt.Println(user)

    // Обновление записи
    db.Model(&user).Update("Age", 31)

    // Удаление записи
    db.Delete(&user)
}

Ent #

Ent (entgo.io/ent) — ORM с генерацией кода.

Пример работы с Ent:

  1. Установите Ent и создайте схему:
    go install entgo.io/ent/cmd/ent
    ent init User
    
  2. Определите схему:
    package schema
    
    import "entgo.io/ent/schema/field"
    
    type User struct {
        ent.Schema
    }
    
    func (User) Fields() []ent.Field {
        return []ent.Field{
            field.String("name"),
            field.Int("age"),
        }
    }
    
  3. Используйте сгенерированный код:
    client, err := ent.Open("postgres", "user=postgres password=secret dbname=mydb sslmode=disable")
    defer client.Close()
    
    user := client.User.Create().SetName("Иван").SetAge(30).Save(context.Background())
    fmt.Println(user)
    

9.3 Транзакции и обработка ошибок #

Используйте транзакции для обеспечения атомарности операций.

Пример с database/sql:

tx, err := db.Begin()
if err != nil {
    panic(err)
}

_, err = tx.Exec("INSERT INTO accounts (id, balance) VALUES ($1, $2)", 1, 100)
if err != nil {
    tx.Rollback()
    panic(err)
}

_, err = tx.Exec("UPDATE accounts SET balance = balance - 50 WHERE id = $1", 1)
if err != nil {
    tx.Rollback()
    panic(err)
}

err = tx.Commit()
if err != nil {
    panic(err)
}

9.4 Миграции и схема базы данных #

Миграции позволяют управлять изменениями структуры базы данных.

Инструмент GORM: #

go install github.com/go-gormigrate/gormigrate/v2

Пример миграции:

package main

import (
    "gorm.io/gorm"
    "github.com/go-gormigrate/gormigrate/v2"
)

func main() {
    db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
        {
            ID: "20231208_create_users",
            Migrate: func(tx *gorm.DB) error {
                type User struct {
                    ID   uint
                    Name string
                }
                return tx.AutoMigrate(&User{})
            },
            Rollback: func(tx *gorm.DB) error {
                return tx.Migrator().DropTable("users")
            },
        },
    })

    if err := m.Migrate(); err != nil {
        panic(err)
    }
    fmt.Println("Миграция выполнена")
}

9.5 Интеграция с NoSQL #

MongoDB #

Для работы с MongoDB используйте драйвер go.mongodb.org/mongo-driver.

Пример подключения и запроса:

package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "time"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        panic(err)
    }

    collection := client.Database("testdb").Collection("users")

    // Добавление документа
    res, err := collection.InsertOne(ctx, bson.M{"name": "Иван", "age": 30})
    fmt.Println("ID добавленного документа:", res.InsertedID)

    // Чтение документа
    var user bson.M
    err = collection.FindOne(ctx, bson.M{"name": "Иван"}).Decode(&user)
    fmt.Println("Найденный пользователь:", user)
}

Redis #

Для работы с Redis используйте пакет github.com/redis/go-redis/v9.

Пример:

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

func main() {
    ctx := context.Background()
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    // Установка ключа
    rdb.Set(ctx, "name", "Иван", 0)

    // Чтение ключа
    name, _ := rdb.Get(ctx, "name").Result()
    fmt.Println("Имя:", name)
}

Эти инструменты позволяют эффективно работать как с реляционными, так и с NoSQL базами данных, покрывая широкий спектр задач.