Назван подготовленный оператор в pgx lib, как он работает?

Вступление

базы данных / SQL

В стандартной библиотеке SQL Go *Stmt Тип имеет методы, определенные как:

func (s *Stmt) Exec(args ...interface{}) (Result, error)
func (s *Stmt) Query(args ...interface{}) (*Rows, error)

Новый (неназванный) оператор подготовлен:

func (db *DB) Prepare(query string) (*Stmt, error)
  1. Пул подключений абстрагирован и не доступен напрямую
  2. Сделка подготовлена ​​на одном подключении
  3. Если соединение не доступно во время выполнения устава, оно будет повторно подготовлено для нового соединения.

PGX

PreparedStatement Тип не имеет методов, определенных. Новое именованное подготовленное заявление подготовлено:

func (p *ConnPool) Prepare(name, sql string) (*PreparedStatement, error)
  1. Операции находятся непосредственно в пуле соединений
  2. Транзакция готовится на всех соединениях пула
  3. Не существует четкого способа выполнения подготовленного оператора

В комментарии к Github автор лучше объясняет различия архитектуры между pgx и database / sql. Документация по Prepare Также говорится (выделено мое):

Приготовьтесь - идемпотент; то есть безопасно вызывать Prepare несколько раз с одним и тем же именем и аргументами sql. Это позволяет использовать код пути Prepare и Query / Exec / PrepareEx, не беспокоясь о том, подготовлен ли оператор.

Маленький пример

package main

import (
    "github.com/jackc/pgx"
)

func main() {
    conf := pgx.ConnPoolConfig{
        ConnConfig: pgx.ConnConfig{
            Host:     "/run/postgresql",
            User:     "postgres",
            Database: "test",
        },
        MaxConnections: 5,
    }
    db, err := pgx.NewConnPool(conf)
    if err != nil {
        panic(err)
    }
    _, err = db.Prepare("my-query", "select $1")
    if err != nil {
        panic(err)
    }
    // What to do with the prepared statement?
}

Вопросы)

  1. name аргумент создает у меня впечатление, что его можно выполнить, вызвав его name, но как?
  2. Документация создает впечатление, что Query / Exec методы каким-то образом используют подготовленные заявления. Однако эти методы не требуют name аргумент. Как это соответствует им?
  3. Предположительно, сопоставление выполняется по содержанию запроса. Тогда в чем смысл именования утверждений?

Возможные ответы

Вот как далеко я попал:

  1. Нет методов, которые ссылаются на запросы по имени (предположение)
  2. Соответствие выполняется в теле запроса в conn.ExecEx(), Если это еще не подготовлено, это будет сделано:
ps, ok := c.preparedStatements[sql]
            if !ok {
                var err error
                ps, err = c.prepareEx("", sql, nil)
                if err != nil {
                    return "", err
                }
            }
  1. Самому PosgreSQL это нужно для чего-то (предположение).

1 ответ

Решение

@mkopriva отметила, что sql текст вводил меня в заблуждение. Здесь есть двойная функция. Если sql переменная не соответствует ключу в c.preparedStatements[sql] карта, запрос, содержащийся в sql готовится и новый *PreparedStatement структура назначена ps, Если он соответствует ключу, ps переменная будет указывать на запись карты.

Таким образом, вы можете сделать что-то вроде:

package main

import (
    "fmt"

    "github.com/jackc/pgx"
)

func main() {
    conf := pgx.ConnPoolConfig{
        ConnConfig: pgx.ConnConfig{
            Host:     "/run/postgresql",
            User:     "postgres",
            Database: "test",
        },
        MaxConnections: 5,
    }
    db, err := pgx.NewConnPool(conf)
    if err != nil {
        panic(err)
    }
    if _, err := db.Prepare("my-query", "select $1::int"); err != nil {
        panic(err)
    }
    row := db.QueryRow("my-query", 10)
    var i int
    if err := row.Scan(&i); err != nil {
        panic(err)
    }
    fmt.Println(i)
}
Другие вопросы по тегам