Travailler avec une base de données SQL dans Go

Dans cet article, je liste comment effectuer des opérations de base de données SQL courantes avec Go.

Présentationdatabase/sql

Go propose une API de base de données SQL propre dans sa bibliothèque standarddatabase/sqlpackage, mais les pilotes de base de données spécifiques doivent être installés séparément.

C'est une approche intelligente car elle fournit une interface commune que presque tous les pilotes de base de données implémentent.

Si vous souhaitez utiliser MySQL, vous pouvez utiliserhttps://github.com/go-sql-driver/mysql.

Si vous utilisez PostgreSQL, utilisezhttps://github.com/lib/pq.

Il vous suffit d'inclure la bibliothèque en utilisantimport _, et ledatabase/sqlL'API sera configurée pour activer ce pilote:

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

Ouvrez la connexion à la base de données

Bien que l'objectif soit de l'avoir abstrait, il existe encore des différences dans certains domaines, par exemple dans la façon dont vous vous connectez à une base de données:

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

//… db, err := sql.Open(“mysql”, “theUser:[email protected]/theDbName”) if err != nil { panic(err) }

import “database/sql”
import _ github.com/lib/pq

//… db, err := sql.Open(“postgres”, “user=theUser dbname=theDbName sslmode=verify-full”) if err != nil { panic(err) }

mais une grande partie de l'API réelle est indépendante de la base de données et peut être interchangée assez facilement (sans parler de SQL ici, se référant simplement à l'API de la base de données).

Fermer la connexion à la base de données

Lorsque cela a du sens, vous devez toujours fermer la connexion à la base de données.

Vous pouvez comme d'habitude l'utilisationdeferpour le fermer lorsque la fonction qui ouvre la connexion db se termine:

db, err := sql.Open("postgres", psqlInfo)
defer db.Close()

Extraire les données de la base de données

Sélectionnez une seule ligne

L'interrogation d'une table se fait en 2 étapes. D'abord tu appellesdb.QueryRow(), alors tu appellesScan()sur le résultat.

Exemple:

id := 1
var col string
sqlStatement := `SELECT col FROM my_table WHERE id=$1`
row := db.QueryRow(sqlStatement, id)
err := row.Scan(&col)
if err != nil {
    if err == sql.ErrNoRows {
        fmt.Println("Zero rows found")
    } else {
        panic(err)
    }
}

db.QueryRow()est utilisé pour interroger une seule valeur d'une table.

Signature:

func (db *DB) QueryRow(query string, args ...interface{}) *Row

Il renvoie un pointeur vers undb.Rowévaluer.

(*Row) Scanscanne la ligne, copiant les valeurs de colonne dans le paramètre qui y est passé.

Signature:

func (r *Row) Scan(dest ...interface{}) error

Si plus d'une ligne a été renvoyée, il analyse uniquement la premièreet ignorez le reste.

Si aucune ligne n'a été renvoyée, elle renvoie unErrNoRowsErreur.

var ErrNoRows = errors.New("sql: no rows in result set")

Sélectionnez plusieurs lignes

Pour interroger une seule ligne, nous avons utilisédb.QueryRow(). Pour interroger plusieurs lignes que nous utilisonsdb.Query(), qui renvoie un*Rowsévaluer.

À partir de la documentation:

//Rows is the result of a query. Its cursor starts before  the first row of the result set. Use Next to advance through the rows:

    rows, err := db.Query("SELECT ...")
    ...
    defer rows.Close()
    for rows.Next() {
        var id int
        var name string
        err = rows.Scan(&id, &name)
        ...
    }
     err = rows.Err() // get any error encountered ing iteration
    ...

// Err renvoie l'erreur, le cas échéant, qui a été rencontrée lors de l'itération. // Err peut être appelé après un Close explicite ou implicite.

Nous devons itérer surrows.Next(), ce qui nous permet d'appelerrows.Scan()dans la boucle.

Si une erreur survient lors de la préparation de la ligne suivante, la boucle se termine et nous pouvons obtenir l'erreur en appelantrows.Err():

type Timeline struct {
    Id int
    Content string
}
rows, err := db.Query(`SELECT id, content FROM timeline`)
if err != nil {
    panic(err)
}
defer rows.Close()
for rows.Next() {
    timeline := Timeline{}
    err = rows.Scan(&timeline.Id, &timeline.Content)
    if err != nil {
        panic(err)
    }
    fmt.Println(timeline)
}
err = rows.Err()
if err != nil {
    panic(err)
}

Plus de tutoriels go: