CRUD
CRUD — Create, Read, Update, Delete, ya’ni yaratish, o’qish, yangilash va o’chirish. pgx’da bu to’rt amal uchta metodga tayanadi:
Exec— natija qatorlarini qaytarmaydigan so’rovlar (INSERT,UPDATE,DELETE).QueryRow— aynan bitta qator kutilganda.Query— ko’p qator qaytaradiganSELECT.
Misollar uchun jadval:
CREATE TABLE products (
id bigserial PRIMARY KEY,
name text NOT NULL,
price int NOT NULL
);$1 — parametrli so’rovlar (SQL injection’dan himoya)
Foydalanuvchi kiritgan qiymatni SQL satriga hech qachon yopishtirmang. pgx’da qiymatlar $1, $2 … kabi placeholder’lar orqali alohida uzatiladi — baza ularni kod deb emas, oddiy ma’lumot deb qabul qiladi.
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://gopher:secret@localhost:5432/shop")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
// TO'G'RI: qiymat $1 orqali uzatiladi.
tag, err := pool.Exec(ctx,
"INSERT INTO products (name, price) VALUES ($1, $2)",
"Klaviatura", 250000)
if err != nil {
log.Fatal(err)
}
fmt.Println("qo'shildi:", tag.RowsAffected(), "qator")
}$ go run insert.go
qo'shildi: 1 qatorExec pgconn.CommandTag qaytaradi; RowsAffected() esa nechta qator o’zgarganini aytadi.
INSERT ... RETURNING — yangi ID ni olish
PostgreSQL’da INSERT’dan keyin baza generatsiya qilgan id’ni darhol qaytarib olsa bo’ladi — buning uchun alohida SELECT yozish shart emas. Bitta qator qaytgani uchun QueryRow ishlatamiz.
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://gopher:secret@localhost:5432/shop")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
var id int64
err = pool.QueryRow(ctx,
"INSERT INTO products (name, price) VALUES ($1, $2) RETURNING id",
"Sichqoncha", 120000).Scan(&id)
if err != nil {
log.Fatal(err)
}
fmt.Println("yangi mahsulot ID:", id)
}$ go run returning.go
yangi mahsulot ID: 2Bitta qator o’qish va pgx.ErrNoRows
QueryRow(...).Scan(...) bitta qatorni o’qib, o’zgaruvchilarga joylaydi. Agar qator topilmasa, Scan pgx.ErrNoRows qaytaradi — buni “topilmadi” holati sifatida alohida ushlab olish kerak, aks holda oddiy xato bilan aralashib ketadi.
package main
import (
"context"
"errors"
"fmt"
"log"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://gopher:secret@localhost:5432/shop")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
var name string
var price int
err = pool.QueryRow(ctx,
"SELECT name, price FROM products WHERE id = $1", 999).
Scan(&name, &price)
switch {
case errors.Is(err, pgx.ErrNoRows):
fmt.Println("mahsulot topilmadi")
case err != nil:
log.Fatal(err)
default:
fmt.Printf("%s — %d so'm\n", name, price)
}
}$ go run queryrow.go
mahsulot topilmadi“Topilmadi”ni tekshirishning to’g’ri yo’li — errors.Is(err, pgx.ErrNoRows).
Ko’p qator o’qish: Query va rows.Next
Bir nechta qator qaytganda Query ishlatiladi. Natijani rows.Next() sikli bilan aylanib chiqamiz, har qadamda Scan qilamiz. defer rows.Close() — majburiy, aks holda ulanish havzaga qaytmaydi.
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://gopher:secret@localhost:5432/shop")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
rows, err := pool.Query(ctx,
"SELECT id, name, price FROM products ORDER BY id")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var name string
var price int
if err := rows.Scan(&id, &name, &price); err != nil {
log.Fatal(err)
}
fmt.Printf("#%d %s — %d so'm\n", id, name, price)
}
if err := rows.Err(); err != nil { // sikl davomidagi xatoni tekshiramiz
log.Fatal(err)
}
}$ go run query.go
#1 Klaviatura — 250000 so'm
#2 Sichqoncha — 120000 so'mSikldan keyin rows.Err()’ni tekshirishni unutmang — Next xatolik yuz berganda ham false qaytaradi.
Update va Delete
Ikkalasi ham Exec orqali bajariladi, RowsAffected() esa nechta qatorga tegilganini aytadi — bu “haqiqatan biror qator o’zgardimi?” degan savolga javob beradi.
package main
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
ctx := context.Background()
pool, err := pgxpool.New(ctx, "postgres://gopher:secret@localhost:5432/shop")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
tag, err := pool.Exec(ctx,
"UPDATE products SET price = $1 WHERE id = $2", 199000, 2)
if err != nil {
log.Fatal(err)
}
fmt.Println("yangilandi:", tag.RowsAffected())
tag, err = pool.Exec(ctx, "DELETE FROM products WHERE id = $1", 1)
if err != nil {
log.Fatal(err)
}
fmt.Println("o'chirildi:", tag.RowsAffected())
}$ go run update.go
yangilandi: 1
o'chirildi: 1Manba / batafsil: pkg.go.dev/github.com/jackc/pgx/v5
Bir nechta o’zgarishni “yo hammasi, yo hech biri” tarzida bajarish kerak bo’lsa — Transaksiyalar.