Зачем даже использовать * DB.exec () или подготовленные операторы в Golang? - PullRequest
0 голосов
/ 03 июня 2018

Я использую golang с Postgresql.

Здесь говорится здесь , что для операций, которые не возвращают строки (вставка, удаление, обновление), мы должны использовать exec()

Если имя функции включает в себя Query, оно предназначено для того, чтобы задать вопрос о базе данных и будет возвращать набор строк, даже если оно пустое.Операторы, которые не возвращают строки, не должны использовать функции Query;они должны использовать Exec ().

Тогда говорится: здесь :

Go создает подготовленные заявления для вас под прикрытием.Например, простой db.Query (sql, param1, param2) работает, подготавливая sql, затем выполняя его с параметрами и, наконец, закрывая оператор.

Если query()использует под прикрытием подготовленные заявления зачем мне вообще беспокоиться об использовании подготовленных заявлений?

1 Ответ

0 голосов
/ 03 июня 2018

"Зачем даже использовать db.Exec ()":

Это правда, что вы можете использовать db.Exec и db.Query взаимозаменяемо для выполнения одних и тех же операторов SQL, однако оба метода возвращают разные типы результатов.Если реализовано драйвером, результат, возвращаемый из db.Exec, может сказать вам, сколько строк было затронуто запросом, в то время как db.Query вместо этого возвратит объект row.

Например, допустим, вы хотите выполнитьDELETE, и вы хотите знать, сколько строк было удалено им.Вы можете сделать это либо правильным способом:

res, err := db.Exec(`DELETE FROM my_table WHERE expires_at = $1`, time.Now())
if err != nil {
    panic(err)
}

numDeleted, err := res.RowsAffected()
if err != nil {
    panic(err)
}
print(numDeleted)

, либо более подробным и объективно более дорогим способом:

rows, err := db.Query(`DELETE FROM my_table WHERE expires_at = $1 RETURNING *`, time.Now())
if err != nil {
    panic(err)
}
defer rows.Close()

var numDelete int
for rows.Next() {
    numDeleted += 1
}
if err := rows.Err(); err != nil {
    panic(err)
}
print(numDeleted)

Есть 3-й способ, которым вы можете сделать это с помощью комбинации CTE после postgres., SELECT COUNT, db.QueryRow и row.Scan, но я не думаю, что необходим пример, чтобы показать, насколько необоснованным является подход, который был бы по сравнению с db.Exec.

Еще одна причина для использования db.Exec over db.Query - это когда вас не волнует возвращаемый результат, когда все, что вам нужно, это выполнить запрос и проверить, была ли ошибка или нет.В таком случае вы можете сделать это:

if _, err := db.Exec(`<my_sql_query>`); err != nil {
    panic(err)
}

С другой стороны, вы не можете (можете, но не должны) делать это:

if _, err := db.Query(`<my_sql_query>`); err != nil {
    panic(err)
}

Делать это послеНекоторое время ваша программа будет паниковать с ошибкой, которая говорит что-то вроде too many connections open.Это связано с тем, что вы отбрасываете возвращенное значение db.Rows, не сделав сначала обязательный вызов Close, и в результате вы получаете количество открытых соединений, которые увеличиваются и в итоге достигают лимита сервера.


«или подготовленные заявления на Голанге?»:

Я не думаю, что книга, которую вы цитировали, является правильной.По крайней мере, мне кажется, что вызов db.Query создает новый подготовленный оператор каждый раз, когда он зависит от используемого вами драйвера.

См., Например, эти два раздела queryDC (неэкспортированныйметод, вызываемый db.Query): без подготовленного утверждения и с подготовленным утверждением .

Независимо от того, является ли книга правильной или нет db.Stmt, созданной db.Query будет, если не происходит внутреннего кеширования, выбрасывается после закрытия возвращенного объекта Rows.Если вместо этого вы вручную вызовете db.Prepare, а затем кэшируете и повторно используете возвращенный db.Stmt, вы потенциально можете повысить производительность запросов, которые необходимо часто выполнять.

Чтобы понять, как подготовленный оператор может использоваться дляоптимизировать производительность вы можете посмотреть в официальной документации: https://www.postgresql.org/docs/current/static/sql-prepare.html

...