From 38478f189ac7c96f40b3eb44aa2b19473a8f6776 Mon Sep 17 00:00:00 2001 From: Ilya Sinelnikov Date: Thu, 8 Apr 2021 14:32:08 +0300 Subject: [PATCH] Refresh database/sql slides --- lectures/07-sql/conf/stats.go | 17 +++++++ lectures/07-sql/conn/conn.go | 2 +- lectures/07-sql/hasql/open.go | 34 +++++++++++++ lectures/07-sql/redis/redis.go | 10 ++-- lectures/07-sql/resources/ctx.go | 19 +++++++ lectures/07-sql/sql.slide | 85 +++++++++++++++++++++----------- 6 files changed, 133 insertions(+), 34 deletions(-) create mode 100644 lectures/07-sql/conf/stats.go create mode 100644 lectures/07-sql/hasql/open.go create mode 100644 lectures/07-sql/resources/ctx.go diff --git a/lectures/07-sql/conf/stats.go b/lectures/07-sql/conf/stats.go new file mode 100644 index 0000000..a744a85 --- /dev/null +++ b/lectures/07-sql/conf/stats.go @@ -0,0 +1,17 @@ +package conf + +type DBStats struct { + MaxOpenConnections int // Maximum number of open connections to the database; added in Go 1.11 + + // Pool Status + OpenConnections int // The number of established connections both in use and idle. + InUse int // The number of connections currently in use; added in Go 1.11 + Idle int // The number of idle connections; added in Go 1.11 + + // Counters + WaitCount int64 // The total number of connections waited for; added in Go 1.11 + WaitDuration time.Duration // The total time blocked waiting for a new connection; added in Go 1.11 + MaxIdleClosed int64 // The total number of connections closed due to SetMaxIdleConns; added in Go 1.11 + MaxIdleTimeClosed int64 // The total number of connections closed due to SetConnMaxIdleTime; added in Go 1.15 + MaxLifetimeClosed int64 // The total number of connections closed due to SetConnMaxLifetime; added in Go 1.11 +} diff --git a/lectures/07-sql/conn/conn.go b/lectures/07-sql/conn/conn.go index 14095c8..edbba9f 100644 --- a/lectures/07-sql/conn/conn.go +++ b/lectures/07-sql/conn/conn.go @@ -1,4 +1,4 @@ -package query +package conn import ( "context" diff --git a/lectures/07-sql/hasql/open.go b/lectures/07-sql/hasql/open.go new file mode 100644 index 0000000..5759331 --- /dev/null +++ b/lectures/07-sql/hasql/open.go @@ -0,0 +1,34 @@ +package hasql + +import ( + "log" + + _ "github.com/jackc/pgx/v4/stdlib" + "goalng.yandex/hasql" + "goalng.yandex/hasql/checkers" +) + +func Open() { + dbFoo, _ := sql.Open("pgx", "host=foo") + dbBar, _ := sql.Open("pgx", "host=bar") + cluster, err := hasql.NewCluster( + []hasql.Node{hasql.NewNode("foo", dbFoo), hasql.NewNode("bar", dbBar) }, + checkers.PostgreSQL, + ) + if err != nil { + log.Fatal(err) + } + + node := cluster.Primary() + if err == nil { + log.Fatal(err) + } + + log.Println("Node address", node.Addr) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err = node.DB().PingContext(ctx); err != nil { + log.Fatal(err) + } +} diff --git a/lectures/07-sql/redis/redis.go b/lectures/07-sql/redis/redis.go index d20643e..fb42014 100644 --- a/lectures/07-sql/redis/redis.go +++ b/lectures/07-sql/redis/redis.go @@ -4,25 +4,25 @@ import ( "log" "time" - "github.com/go-redis/redis" + "github.com/go-redis/redis/v8" ) -func Example() { +func Example(ctx context.Context) { rdb := redis.NewUniversalClient(&redis.UniversalOptions{ MasterName: "master", Addrs: []string{":26379"}, }) defer rdb.Close() - if err := rdb.Ping(); err != nil { + if err := rdb.Ping(ctx); err != nil { log.Fatal(err) } - if err := rdb.Set("key", "value", time.Hour).Err(); err != nil { + if err := rdb.Set(ctx, "key", "value", time.Hour).Err(); err != nil { log.Fatal(err) } - value, err := rdb.Get("key").Result() + value, err := rdb.Get(ctx, "key").Result() if err != nil { log.Fatal(err) } diff --git a/lectures/07-sql/resources/ctx.go b/lectures/07-sql/resources/ctx.go new file mode 100644 index 0000000..902adec --- /dev/null +++ b/lectures/07-sql/resources/ctx.go @@ -0,0 +1,19 @@ +package resources + +import ( + "context" + "database/sql" + "log" +) + +func NoContext(ctx context.Context, db *sql.DB) { + // У Conn() нет версии без контекста + c, err := db.Conn(ctx) + if err != nil { + log.Fatal(err) + } + defer c.Close() + + // Потенциально вечный Ping + _ = c.Ping() +} diff --git a/lectures/07-sql/sql.slide b/lectures/07-sql/sql.slide index 5491e8d..8391a44 100644 --- a/lectures/07-sql/sql.slide +++ b/lectures/07-sql/sql.slide @@ -78,6 +78,14 @@ database/sql * Null в результатах .code nulls/rows.go /^func Results/,/^}/ +* Одно подключение + +.code conn/conn.go /^func Conn/,/^}/ + +* Транзакции + +.code tx/tx.go /^func Begin/,/^}/ + * Prepared Statements Плюсы: @@ -92,15 +100,49 @@ database/sql .code prepare/prepare.go /^func Prepare/,/^}/ -* Одно подключение +* *sql.DB - это пул коннектов -.code conn/conn.go /^func Conn/,/^}/ +* Настройка DB -* Транзакции +- func (db *DB) SetConnMaxIdleTime(d time.Duration) +- func (db *DB) SetConnMaxLifetime(d time.Duration) +- func (db *DB) SetMaxIdleConns(n int) +- func (db *DB) SetMaxOpenConns(n int) -.code tx/tx.go /^func Begin/,/^}/ +* Статистика DB -* Типовые ошибки и подводные камни +- func (db *DB) Stats() DBStats + +.code conf/stats.go /^type DBStats/,/^} + +* Подводные камни при работе с database/sql + +* Основные типы граблей + +- исчерпание ресурсов +- дедлоки +- комбинация первого и второго +- нюансы каждого отдельного драйвера + +* Context + +.code resources/ctx.go /^func NoContext/,/^}/ + +* Запросы - исчерпание ресурсов + +.code resources/rows.go /^func RowsExhaust/,/^}/ + +* Коннекты - исчерпание ресурсов + +.code resources/conn.go /^func ConnExhaust/,/^}/ + +* Транзакции - исчерпание ресурсов + +.code resources/tx.go /^func TxExhaust/,/^}/ + +* Транзакции - deadlock + +.code resources/tx.go /^func TxDeadlock/,/^}/ * Запросы - deadlock @@ -114,22 +156,6 @@ database/sql .code resources/queries.go /^func QueryDeadlockFixTwo/,/^}/ -* Запросы - исчерпание ресурсов - -.code resources/rows.go /^func RowsExhaust/,/^}/ - -* Транзакции - исчерпание ресурсов - -.code resources/tx.go /^func TxExhaust/,/^}/ - -* Транзакции - deadlock - -.code resources/tx.go /^func TxDeadlock/,/^}/ - -* Коннекты - исчерпание ресурсов - -.code resources/conn.go /^func ConnExhaust/,/^}/ - * Удобства и расширения * github.com/jmoiron/sqlx @@ -142,12 +168,6 @@ database/sql .code sqlx/open.go -* sqlx - обобщенный интерфейс - -.code sqlx/ext.go /^type QueryerContext/,/^}/ -.code sqlx/ext.go /^type ExecerContext/,/^}/ -.code sqlx/ext.go /^type ExtContext/,/^}/ - * sqlx - StructScan func (r *Rows) StructScan(dest interface{}) error @@ -175,6 +195,15 @@ database/sql .code sqlx/named.go /^func Insert/,/^}/ +* golang.yandex/hasql + +- удобная работа с многохостовыми кластерами +- поддерживает database/sql и sqlx + +* hasql - подключение и использование + +.code hasql/open.go /^func Open/,/^}/ + * Нетипичные драйверы * Нетипичные драйверы - github.com/DATA-DOG/go-sqlmock @@ -202,7 +231,7 @@ database/sql .link https://github.com/go-sql-driver/mysql - MySQL .link https://github.com/ClickHouse/clickhouse-go - ClickHouse -Разное: +Другие: .link https://github.com/go-redis/redis - Redis .link https://github.com/mongodb/mongo-go-driver - MongoDB