Определите, использовать ли DB.Exec или DB.Query из неизвестной строки запроса - PullRequest
1 голос
/ 03 октября 2019

Используя "database/sql", sql.DB.Exec() используется для запросов, которые не возвращают строки (insert, delete, update) и sql.DB.Query() для запросов, которые возвращают строки (selects). Предположим, у вас есть входящая строка запроса, которую вы хотите выполнить, однако вы не знаете, намеревается ли запрос вернуть строки. Можете ли вы найти способ выяснить, использовать ли Exec или Query?

Ответы [ 2 ]

1 голос
/ 06 октября 2019

В любом случае, не пытайтесь анализировать SQL, так как он хакерский. Просто используйте Query, если вы не уверены, Query должен уметь хорошо обрабатывать C_UD и возвращать пустой набор результатов в этом случае. И Query, и Exec должны иметь одинаковый эффект, и они различаются только по своему отклику. Используйте Exec, только если пользователю вашего API явно не нужны результаты.

0 голосов
/ 06 октября 2019

Ваш вопрос не так прост, как может показаться на первый взгляд.

1. Давайте проясним проблему

Вопрос не о конкретной базе данных, такой как pgsql / mysql / sqlite / other, а о любом общем диске базы данных.

Таким образом, ответ должен быть в database/sql/driver. Пойдем дальше.

2. sql/driver. Интерфейсы: Queryer / QueryerContext & Execer / ExecerContext

Модуль sql/driver определяет интерфейсы:

  • Queryer / QeueryerContext - для возможности(*DB).Query
  • Execer / ExecerContext - для (*DB).Exec
  • других, таких как Pinger

Обратите внимание, что каждый интерфейс описан в документации как "дополнительный интерфейс, который может быть реализован с помощью Conn"

Это означает, что можно реализовать драйвер sql без Query и / или Exec.

3. Экспериментальная проверка

Давайте попробуем реализовать правильный драйвер базы данных, который не может Query и Exec: https://play.golang.org/p/sZiigEghphE

package main

import (
    "database/sql"
    "database/sql/driver"
    "log"
)

type expdrv struct{}
type expconn struct{}

// sql.Driver implementation
func (*expdrv) Open(name string) (driver.Conn, error) {
    return &expconn{}, nil
}

// driver.Conn implementation
func (c *expconn) Prepare(query string) (driver.Stmt, error) {
    return nil, nil
}

func (c *expconn) Close() error {
    return nil
}

func (c *expconn) Begin() (driver.Tx, error) {
    return nil, nil
}

func main() {
    sql.Register("drvexp", &expdrv{})
    log.Printf("Registred drivers: %v\n", sql.Drivers())

    db, err := sql.Open("drvexp", "")
    log.Printf("sql.Open() success: %v, error: %v", db != nil, err)

    log.Println("db.Close() error:", db.Close())
}
2009/11/10 23:00:00 Registred drivers: [drvexp]
2009/11/10 23:00:00 sql.Open() success: true, error: 
2009/11/10 23:00:00 db.Ping()  success: true
2009/11/10 23:00:00 db.Close() success: true
2009/11/10 23:00:00 db.Ping()  result:  sql: database is closed

Это работает! Эта реализация Driver:

  • правильно с database/sql точки зрения
  • не имеет методов работы Query и Exec (попытка вызовет панику)
  • удивительно работающий Ping()

4. Возможность реализации Exec или Query независимо друг от друга

Давайте добавим Exec:

// driver.Result & driver.Execer
type expresult struct{}

func (*expconn) Exec(query string, args []driver.Value) (driver.Result, error) {
    return &expresult{}, nil
}

func (*expresult) LastInsertId() (int64, error) {
    return 0, nil
}

func (*expresult) RowsAffected() (int64, error) {
    return 0, nil
}

позволит:

_, err = db.Exec("BYE")
fmt.Println("db.Exec() success:", err == nil) // Outputs: true

5. Заключение

  • Возможность вызова Query/QueryContext и / или Exec/ExecContext является необязательной

  • Поведение этих методов может сильно различаться у разных драйверов

  • В общем случае правильного ответа не существует

  • Для особых случаев (с определенным драйвером):

    • можно предположить , что db.Query будет работать в большинстве случаев
    • , но невозможно гарантировать , что Query действительно будет работатьбез экспериментальной проверки

Спасибо за внимание!

Полагаю, это окончательный ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...