Назван подготовленный оператор в pgx lib, как он работает? - PullRequest
0 голосов
/ 10 февраля 2019

Введение

база данных / 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
                }
            }
Самому PosgreSQL это нужно для чего-то (предположение).

1 Ответ

0 голосов
/ 13 февраля 2019

@ 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)
}
...