Skip to content

Commit f49d806

Browse files
author
Leonid Moguchev
committed
pgx
1 parent c15fa3d commit f49d806

File tree

6 files changed

+448
-15
lines changed

6 files changed

+448
-15
lines changed

README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
# postgres
22

3-
Краткий tutorial для работы с postgres в Go.
3+
Краткий пример работы с PostgreSQL в Go.
4+
5+
- *./database-sql* - пример работы со стандартной библиотекой __database/sql__
6+
- *./sqlx* - пример работы с расширением стандартной библиотеки __sqlx__
7+
- *./pgx* - пример работы с __pgx__
8+
9+
Запуск БД:
10+
* `make up-dp`
11+
12+

database-sql/main.go

+31-12
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import (
1212

1313
// database/sql — это набор интерфейсов для работы с базой
1414
// Чтобы эти интерфейсы работали, для них нужна реализация. Именно за реализацию и отвечают драйверы.
15+
1516
_ "github.com/lib/pq" // импортируем драйвер для postgres
1617
// Обратите внимание, что мы загружаем драйвер анонимно, присвоив его квалификатору пакета псевдоним, _ ,
1718
// чтобы ни одно из его экспортированных имен не было видно нашему коду.
1819
// Под капотом драйвер регистрирует себя как доступный для пакета database/sql
1920
)
2021

2122
const (
22-
2323
// название регистрируемоего драйвера github.com/lib/pq
2424
stdPostgresDriverName = "postgres"
2525
/*
@@ -48,7 +48,6 @@ const (
4848
)
4949

5050
func main() {
51-
5251
// connection string
5352
psqlConn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
5453

@@ -100,6 +99,7 @@ func main() {
10099
/* примеры работы c БД c контекстом */
101100
// Совет: используйте запросы с контекстом
102101
ctx := context.Background()
102+
103103
exampleQueryRowContext(ctx, db)
104104
exampleQueryContext(ctx, db)
105105
exampleExecContext(ctx, db)
@@ -127,8 +127,12 @@ func exampleQueryRow(db *sql.DB) {
127127

128128
// Ex. 2
129129
var studentID int64
130-
row = db.QueryRow("SELECT id FROM students WHERE age > 10000") // такого "долгожителя" в нашей таблице может не быть
131-
if err := row.Scan(&studentID); err != nil { // мы тут получим ошубку, так как нам ничего не вернулось из БД
130+
row = db.QueryRow("SELECT id FROM students WHERE age = 10000") // такого "долгожителя" в нашей таблице может не быть
131+
if errors.Is(row.Err(), sql.ErrNoRows) {
132+
fmt.Println("Не найден в БД студент с age > 10000")
133+
}
134+
135+
if err := row.Scan(&studentID); err != nil { // мы тут получим ошубку, так как нам ничего не вернулось из БД
132136
fmt.Println("db.QueryRow.Scan():", err) // нам вернется ошибка sql.ErrNoRows
133137
if errors.Is(err, sql.ErrNoRows) { // при использовании QueryRow не забывайте обрабатывать ошибку на sql.ErrNoRows, так как отстуствие результата может быть стандартным кейсом
134138
fmt.Println("Не найден в БД студент с age > 10000")
@@ -262,8 +266,8 @@ func exampleExecContext(ctx context.Context, db *sql.DB) {
262266
func exampleTransaction(ctx context.Context, db *sql.DB) {
263267
// создаем транзакцию
264268
tx, err := db.BeginTx(ctx, &sql.TxOptions{
265-
Isolation: sql.LevelRepeatableRead, // указываем в опциях уровень изоляции
266-
ReadOnly: false, // можем указать, что транзакции только для чтения
269+
Isolation: sql.LevelSerializable, // указываем в опциях уровень изоляции
270+
ReadOnly: false, // можем указать, что транзакции только для чтения
267271
})
268272
if err != nil {
269273
log.Fatal(err)
@@ -275,7 +279,7 @@ func exampleTransaction(ctx context.Context, db *sql.DB) {
275279
if err != nil {
276280
log.Fatal(err)
277281
}
278-
rows.Close()
282+
defer rows.Close()
279283

280284
_, err = tx.ExecContext(ctx, "SELECT 1")
281285
if err != nil {
@@ -353,23 +357,38 @@ func exampleWithNullableFields(ctx context.Context, db *sql.DB) {
353357
}
354358

355359
type MyCustomType struct {
356-
Valid bool
357360
Number int
361+
Valid bool
358362
}
359363

360364
// Scan implements the Scanner interface.
361-
func (n *MyCustomType) Scan(value interface{}) error {
362-
if value == nil {
365+
func (n *MyCustomType) Scan(src interface{}) error {
366+
// The src value will be of one of the following types:
367+
//
368+
// int64
369+
// float64
370+
// bool
371+
// []byte
372+
// string
373+
// time.Time
374+
// nil - for NULL values
375+
if src == nil {
363376
n.Number, n.Valid = 0, false
364377
return nil
365378
}
366379
n.Valid = true
367380

368381
// some fantastic logic here
369-
fmt.Printf("%#v\n", value)
382+
switch src := src.(type) {
383+
case int64:
384+
n.Number = int(src)
385+
case bool:
386+
n.Number = 1
387+
default:
388+
return fmt.Errorf("can't scan %#v into MyCustomType", src)
389+
}
370390

371391
return nil
372-
373392
}
374393

375394
var _ sql.Scanner = (*MyCustomType)(nil) // наш тип MyCustomType удовлетовряет интерфейсу sql.Scanner

go.mod

+17
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,23 @@ module github.com/moguchev/postgres
33
go 1.17
44

55
require (
6+
github.com/georgysavva/scany v0.3.0 // indirect
7+
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
8+
github.com/jackc/pgconn v1.12.1 // indirect
9+
github.com/jackc/pgio v1.0.0 // indirect
10+
github.com/jackc/pgpassfile v1.0.0 // indirect
11+
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
12+
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
13+
github.com/jackc/pgtype v1.11.0 // indirect
14+
github.com/jackc/pgx v3.6.2+incompatible // indirect
15+
github.com/jackc/pgx/v4 v4.16.1 // indirect
16+
github.com/jackc/puddle v1.2.1 // indirect
617
github.com/jmoiron/sqlx v1.3.4 // indirect
718
github.com/lib/pq v1.10.5 // indirect
19+
github.com/pkg/errors v0.9.1 // indirect
20+
go.uber.org/atomic v1.7.0 // indirect
21+
go.uber.org/multierr v1.6.0 // indirect
22+
go.uber.org/zap v1.21.0 // indirect
23+
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
24+
golang.org/x/text v0.3.7 // indirect
825
)

0 commit comments

Comments
 (0)