MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Lucrul cu bazele de date relaționale

Pentru a lucra cu bazele de date relaționale în Go, se folosește pachetul încorporat database/sql. Totuși, acesta nu se folosește de unul singur. El doar furnizează o interfață universală pentru lucrul cu bazele de date. Pentru a lucra cu un SGBD specific, avem nevoie și de un driver. Lista driverelor disponibile o puteți găsi aici. Totuși, deoarece driverele implementează aceleași interfețe, în principiu, lucrul cu diferite SGBD-uri va fi similar.

Pentru a începe lucrul cu baza de date, trebuie să deschidem o conexiune folosind funcția Open():

func Open(driverName, dataSourceName string) (*DB, error)

Această funcție primește ca parametri numele driverului și numele sursei de date la care trebuie să ne conectăm. Funcția returnează un obiect DB, care reprezintă baza de date cu care putem lucra. Dacă conexiunea nu reușește, informațiile despre eroare vor fi disponibile în obiectul error.

Apoi, interacțiunea cu baza de date se face prin metodele obiectului DB.

func (db *DB) Exec(query string, args ...interface{}) (Result, error)
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
func (db *DB) QueryRow(query string, args ...interface{}) *Row
func (db *DB) Close() error         // închide conexiunea

Metoda Exec() execută o expresie SQL care este trecută prin primul parametru, fără a returna un rezultat. Metoda acceptă, de asemenea, parametri suplimentari, prin care se pot transmite valori către expresia SQL. De exemplu, o operațiune abstractă de adăugare a datelor într-o bază de date, care presupune executarea comenzii INSERT:

result, err := db.Exec("INSERT INTO Products (model, company, price) VALUES ('iPhone X', 'Apple', 72000)")

Modul de inserare a parametrilor suplimentari într-o expresie SQL depinde de driverul specific. De asemenea, această metodă este folosită pentru executarea comenzilor UPDATE (actualizare) și DELETE (ștergere).

Metoda returnează un obiect Result. Această interfață definește două metode:

  • LastInsertId() (int64, error) // returnează id-ul ultimei linii care a fost adăugată/actualizată/ștearsă
  • RowsAffected() (int64, error) // returnează numărul de linii afectate

Metoda Query() este folosită pentru a executa o interogare care returnează date. De obicei, aceste interogări conțin comenzi SELECT.

rows, err := db.Query("SELECT name FROM users WHERE age=23")

Rezultatul interogării este un obiect *Rows, care este practic un set de linii. Folosind diverse metode ale acestui obiect, putem extrage datele obținute:

func (rs *Rows) Columns() ([]string, error)     // returnează numele coloanelor din set
func (rs *Rows) Next() bool                     // returnează true dacă există o altă linie în set și se mută la ea
func (rs *Rows) Scan(dest ...interface{}) error     // citește datele din linie în variabile
func (rs *Rows) Close() error                   // închide obiectul Rows pentru citiri ulterioare

Principiul general de citire al unui set de linii arată cam așa:

rows, err := db.Query("SELECT ...")
...
defer rows.Close()
for rows.Next() {
    var id int
    var name string
    rows.Scan(&id, &name)
    fmt.Println(id, name)
}

Mai întâi, executăm interogarea la baza de date folosind metoda db.Query, apoi folosind metoda Next() citim fiecare linie din set. Dacă nu mai sunt linii în set, metoda returnează false, iar ciclul se oprește. Dacă mai există linii, obiectul *Rows se mută la următoarea linie. Apoi, putem citi datele din linia curentă folosind metoda Scan().

Metoda QueryRow() returnează o singură linie sub forma unui obiect *Row. De obicei, această metodă este folosită pentru a obține un obiect unic, de exemplu, pe baza unui id. Acest obiect are o metodă Scan(), care permite extragerea datelor din linie:

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

De asemenea, merită menționat că Go susține crearea de interogări folosind obiectul Stmt, care permite inserarea de date diferite și care îmbunătățește performanța. De asemenea, Go suportă tranzacțiile prin obiectul Tx.

Toate aceste lucruri sunt implementate diferit de către driverele pentru sistemele de gestionare a bazelor de date specifice. Însă principiile generale vor fi aceleași. Astfel, structura generală de lucru cu diferite baze de date va fi similară datorită aceleași interfețe.