PostgreSQL

Последнее обновление: 31.01.2018

Для работы с PostgreSQL в Go мы можем применять различные драйверы, но в данном случае мы будем использовать Pure Go Postgres driver.

Поэтому начале перейдем в командную строку/терминал и установим данный драйвер с помощью команды

go get github.com/lib/pq

Пусть на сервере PostgreSQL будет база данных productdb, в которой есть таблица Products, описываемая следующим скриптом:

CREATE TABLE Products (
    id    integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    model  varchar(30) NOT NULL,
    company varchar(30) NOT NULL,
    price integer NOT NULL
);

То есть в таблице будет четыре столбца: id, model, company, price.

Открытие подключения

Для открытия соединения с базой данных в функцию sql.Open() передается имя драйвера "postgres" и строка подключения:

connStr := "user=postgres password=mypass dbname=productdb sslmode=disable"
db, err := sql.Open("postgres", connStr)

Строка подключения инкапсулирует следующие параметры: user (логин на сервере PostgreSQL), password (пароль этого пользователя), dbname (имя базы данных), sslmode (режим работы с SSL). В моем случае логин - postgres (логин по умолчанию на сервере), пароль - mypass, имя базы данных - productdb (которая была создана выше) и ssl отключен (значение disable).

В результате установки подлючения метод db.Open возвратить объект *DB, через который можно будет взаимодействовать в базой данных.

Это не все возможные параметры. Полный список параметров для строки подключения и их значения можно посмотреть в документации.

Добавление данных

Для добавления используется метод Exec():

package main
import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)

func main() { 

	connStr := "user=postgres password=mypass dbname=productdb sslmode=disable"
	db, err := sql.Open("postgres", connStr)
	if err != nil {
		panic(err)
	} 
	defer db.Close()
	
	result, err := db.Exec("insert into Products (model, company, price) values ('iPhone X', $1, $2)", 
		"Apple", 72000)
	if err != nil{
		panic(err)
	}
	fmt.Println(result.LastInsertId())	// не поддерживается
	fmt.Println(result.RowsAffected())	// количество добавленных строк
}

Выполняемое sql-выражение может получать значения через дополнительные параметры метода db.Exec(). В самом sql-выражении такие значения представлены плейсхолдерами $1, $2 и так далее, вместо которых вставляются значения дополнительных параметров метода db.Exec.

Стоит обратить внимание, что этот драйвер не поддерживает метод result.LastInsertId(), который возвращает id последнего добавленного объекта:

Добавление в базу данных PostgreSQL в языке Go

Если нам обязательно нужно получить id добавленного объекта, то мы можем использовать метод db.QueryRow(), который выполняет запрос и возвращает определенный объект:

var id int
db.QueryRow("insert into Products (model, company, price) values ('Mate 10 Pro', $1, $2) returning id", 
	"Huawei", 35000).Scan(&id)
fmt.Println(id)

В само sql выражение вводится подвыражение "returning id". И с помощью метода Scan() полученное значение считывается в переменную id.

Получение данных

Для получения данных применяется метод db.Query(), который возващает набор строк, либо db.QueryRow(), который возвращает одну строку:

package main
import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)

type product struct{
	id int
	model string
	company string
	price int
}
func main() { 

	connStr := "user=postgres password=mypass dbname=productdb sslmode=disable"
	db, err := sql.Open("postgres", connStr)
	if err != nil {
		panic(err)
	} 
	defer db.Close()
	
	rows, err := db.Query("select * from Products")
	if err != nil {
		panic(err)
	}
	defer rows.Close()
	products := []product{}
	
	for rows.Next(){
		p := product{}
		err := rows.Scan(&p.id, &p.model, &p.company, &p.price)
		if err != nil{
			fmt.Println(err)
			continue
		}
		products = append(products, p)
	}
	for _, p := range products{
		fmt.Println(p.id, p.model, p.company, p.price)
	}
}

Для работы с данными здесь определена структура product, которая соответствует данным в таблице Products.

Для получения данных вызывается метод Query():

rows, err := db.Query("select * from Products")

Этот метод в качестве параметра принимает sql-выражение SELECT на получение всех данных из таблицы Products. Результат выборки попадает в переменную rows, которая представляет указатель на структуру Rows. И с помощью метода rows.Next() мы можем последовательно перебрать все строки в полученном наборе:

for rows.Next(){
	p := product{}
	err := rows.Scan(&p.id, &p.model, &p.company, &p.price)
	if err != nil{
		fmt.Println(err)
		continue
	}
	products = append(products, p)
}

Тип Rows определяет метод Scan, с помощью которого можно считать все полученные данные в переменные. Например, здесь считываем данные в структуру Product и затем добавляем ее в срез. Поскольку мы получаем все данные - все четыре столбца, то соответственно в Scan передается адреса четырех переменных.

После прочтения данных в срез мы можем делать с ними все что угодно, например, вывести на консоль:

Получение данных из базы данных PostgreSQL в языке Go

В методе Query мы можем указывать дополнительные параметры. Например, получим товары, у которых цена больше 70000:

rows, err := db.Query("select * from Products where price > $1", 70000)

Если надо получить только одну строку, то можно использовать метод QueryRow():

row := db.QueryRow("select * from Products where id = $1", 2)
prod := product{}
err = row.Scan(&prod.id, &prod.model, &prod.company, &prod.price)
if err != nil{
	panic(err)
}
fmt.Println(prod.id, prod.model, prod.company, prod.price)

Обновление

Для обновления данных применяется метод Exec:

package main
import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)
func main() { 

	connStr := "user=postgres password=mypass dbname=productdb sslmode=disable"
	db, err := sql.Open("postgres", connStr)
	if err != nil {
		panic(err)
	} 
	defer db.Close()
	
	// обновляем строку с id=1
	result, err := db.Exec("update Products set price = $1 where id = $2", 69000, 1)
	if err != nil{
		panic(err)
	}
	fmt.Println(result.RowsAffected())	// количество обновленных строк
}

Удаление

Для удаления также применяется метод Exec:

package main
import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)
func main() { 

	connStr := "user=postgres password=mypass dbname=productdb sslmode=disable"
	db, err := sql.Open("postgres", connStr)
	if err != nil {
		panic(err)
	} 
	defer db.Close()
	
	// удаляем строку с id=2
	result, err := db.Exec("delete from Products where id = $1", 2)
	if err != nil{
		panic(err)
	}
	fmt.Println(result.RowsAffected())	// количество удаленных строк
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850