@@ -3,34 +3,47 @@ layout: article
3
3
title : Using Prepared Statements
4
4
---
5
5
6
+ 使用准备好的陈述
7
+
6
8
Prepared statements have all the usual benefits in Go: security, efficiency,
7
9
convenience. But the way they're implemented is a little different from what
8
10
you might be used to, especially with regards to how they interact with some of
9
11
the internals of ` database/sql ` .
10
12
13
+ 准备好的陈述在Go中具有所有常见的好处:安全性,效率和便利性。但是它们的实现方式与您可能习惯的方式略有不同,特别是关于它们如何与 ` database/sql ` 的某些内部进行交互。
14
+
11
15
Prepared Statements And Connections
12
16
===================================
13
17
18
+ 准备好的陈述和连接
19
+
14
20
At the database level, a prepared statement is bound to a single database
15
21
connection. The typical flow is that the client sends a SQL statement with
16
22
placeholders to the server for preparation, the server responds with a statement
17
23
ID, and then the client executes the statement by sending its ID and parameters.
18
24
25
+ 在数据库级别,预准备语句绑定到单个数据库连接。典型的流程是客户端将带有占位符的SQL语句发送到服务器进行准备,服务器使用语句ID进行响应,然后客户端通过发送其ID和参数来执行该语句。
26
+
19
27
In Go, however, connections are not exposed directly to the user of the
20
28
` database/sql ` package. You don't prepare a statement on a connection. You
21
29
prepare it on a ` DB ` or a ` Tx ` . And ` database/sql ` has some convenience
22
30
behaviors such as automatic retries. For these reasons, the underlying
23
31
association between prepared statements and connections, which exists at the
24
32
driver level, is hidden from your code.
25
33
34
+ 但是,在Go中,连接不会直接暴露给database / sql包的用户。您没有在连接上准备语句。您在DB或Tx上准备它。并且database / sql具有一些便利行为,例如自动重试。由于这些原因,在驱动程序级别存在的预准备语句和连接之间的底层关联对代码是隐藏的。
35
+
26
36
Here's how it works:
27
37
28
- 1 . When you prepare a statement, it's prepared on a connection in the pool.
29
- 2 . The ` Stmt ` object remembers which connection was used.
38
+ 1 . When you prepare a statement, it's prepared on a connection in the pool.
39
+ 准备语句时,它是在池中的连接上准备的。
40
+ 2 . The ` Stmt ` object remembers which connection was used.
41
+ Stmt对象会记住使用了哪个连接。
30
42
3 . When you execute the ` Stmt ` , it tries to use the connection. If it's not
31
43
available because it's closed or busy doing something else, it gets another
32
44
connection from the pool *and re-prepares the statement with the database on
33
- another connection.*
45
+ another connection.*
46
+ 执行Stmt时,它会尝试使用该连接。如果由于它已关闭或忙于执行其他操作而无法使用,它将从池中获取另一个连接,并在另一个连接上使用数据库重新准备语句。
34
47
35
48
Because statements will be re-prepared as needed when their original connection
36
49
is busy, it's possible for high-concurrency usage of the database, which may
@@ -39,31 +52,45 @@ This can result in apparent leaks of statements, statements being prepared and
39
52
re-prepared more often than you think, and even running into server-side limits
40
53
on the number of statements.
41
54
55
+ 因为在原始连接繁忙时将根据需要重新准备语句,所以数据库的高并发使用可能会使很多连接繁忙,从而创建大量预准备语句。这可能导致语句的明显泄漏,正在准备和重新准备的语句比您想象的更频繁,甚至在语句数量上遇到服务器端限制。
56
+
42
57
Avoiding Prepared Statements
43
58
============================
44
59
60
+ 避免准备好的陈述
61
+
45
62
Go creates prepared statements for you under the covers. A simple
46
63
` db.Query(sql, param1, param2) ` , for example, works by preparing the sql, then
47
64
executing it with the parameters and finally closing the statement.
48
65
66
+ Go为您创建了准备好的陈述。例如,一个简单的db.Query(sql,param1,param2)通过准备sql,然后使用参数执行它并最终关闭语句来工作。
67
+
49
68
Sometimes a prepared statement is not what you want, however. There might be
50
69
several reasons for this:
51
70
71
+ 但是,有时准备好的陈述不是你想要的。可能有以下几种原因:
72
+
52
73
1 . The database doesn't support prepared statements. When using the MySQL
53
74
driver, for example, you can connect to MemSQL and Sphinx, because they
54
75
support the MySQL wire protocol. But they don't support the "binary" protocol
55
- that includes prepared statements, so they can fail in confusing ways.
76
+ that includes prepared statements, so they can fail in confusing ways.
77
+
78
+ 数据库不支持预准备语句。例如,当使用MySQL驱动程序时,您可以连接到MemSQL和Sphinx,因为它们支持MySQL线程协议。但是它们不支持包含预准备语句的“二进制”协议,因此它们可能会以混乱的方式失败。
56
79
2 . The statements aren't reused enough to make them worthwhile, and security
57
80
issues are handled in other ways, so performance overhead is undesired. An
58
81
example of this can be seen at the
59
- [VividCortex blog](https://vividcortex.com/blog/2014/11/19/analyzing-prepared-statement-performance-with-vividcortex/).
82
+ [VividCortex blog](https://vividcortex.com/blog/2014/11/19/analyzing-prepared-statement-performance-with-vividcortex/).
83
+
84
+ 这些语句的重用不足以使它们变得有价值,并且安全问题以其他方式处理,因此不希望出现性能开销。可以在VividCortex博客上看到这方面的一个例子。
60
85
61
86
If you don't want to use a prepared statement, you need to use ` fmt.Sprint() ` or
62
87
similar to assemble the SQL, and pass this as the only argument to ` db.Query() `
63
88
or ` db.QueryRow() ` . And your driver needs to support plaintext query execution,
64
89
which is added in Go 1.1 via the ` Execer ` and ` Queryer ` interfaces,
65
90
[ documented here] ( http://golang.org/pkg/database/sql/driver/#Execer ) .
66
91
92
+ 如果您不想使用预准备语句,则需要使用 ` fmt.Sprint() ` 或类似语法来组装SQL,并将其作为 ` db.Query() ` 或 ` db.QueryRow() ` 的唯一参数传递。并且您的驱动程序需要支持明文查询执行,这是通过此处记录的 ` Execer ` 和 ` Queryer ` 接口在Go 1.1中添加的。
93
+
67
94
Prepared Statements in Transactions
68
95
===================================
69
96
@@ -72,20 +99,28 @@ it, so the earlier cautions about repreparing do not apply. When
72
99
you operate on a ` Tx ` object, your actions map directly to the one and only one
73
100
connection underlying it.
74
101
102
+ 在Tx中创建的预处理语句仅与其绑定,因此之前关于重新表示的警告不适用。当您对Tx对象进行操作时,您的操作将直接映射到其下的唯一连接。
103
+
75
104
This also means that prepared statements created inside a ` Tx ` can't be used
76
105
separately from it. Likewise, prepared statements created on a ` DB ` can't be
77
106
used within a transaction, because they will be bound to a different connection.
78
107
108
+ 这也意味着在Tx中创建的预处理语句不能与它分开使用。同样,在DB上创建的预准备语句不能在事务中使用,因为它们将绑定到不同的连接。
109
+
79
110
To use a prepared statement prepared outside the transaction in a ` Tx ` , you can use
80
111
` Tx.Stmt() ` , which will create a new transaction-specific statement from the one
81
112
prepared outside the transaction. It does this by taking an existing prepared statement,
82
113
setting the connection to that of the transaction and repreparing all statements every
83
114
time they are executed. This behavior and its implementation are undesirable and there's
84
115
even a TODO in the ` database/sql ` source code to improve it; we advise against using this.
85
116
117
+ 要在Tx中使用在事务外部准备的预准备语句,可以使用Tx.Stmt(),它将从事务外部准备的语句创建新的特定于事务的语句。它通过获取现有的预准备语句,将连接设置为事务的连接并在每次执行时重新表示所有语句来完成此操作。这种行为及其实现是不可取的,在数据库/ sql源代码中甚至还有一个TODO来改进它;我们建议不要使用它。
118
+
86
119
Caution must be exercised when working with prepared statements in
87
120
transactions. Consider the following example:
88
121
122
+ 在交易中处理准备好的报表时必须谨慎行事。请考虑以下示例:
123
+
89
124
<pre class =" prettyprint lang-go " >
90
125
tx, err := db.Begin()
91
126
if err != nil {
@@ -118,6 +153,8 @@ underlying connection, rendering the connection state inconsistent.
118
153
If you use Go 1.4 or older, you should make sure the statement is always closed before the transaction is
119
154
committed or rolled back. [ This issue] ( https://github.com/golang/go/issues/4459 ) was fixed in Go 1.4 by [ CR 131650043] ( https://codereview.appspot.com/131650043 ) .
120
155
156
+ 在Go 1.4关闭之前,* sql.Tx将与之关联的连接释放回池中,但是在已经发生的情况下执行了对准备好的语句的延迟调用Close,这可能导致并发访问底层连接,从而呈现连接状态不一致。如果使用Go 1.4或更早版本,则应确保在提交或回滚事务之前始终关闭该语句。 CR 131650043在Go 1.4中修复了此问题。
157
+
121
158
Parameter Placeholder Syntax
122
159
============================
123
160
0 commit comments