金正亿家 發表於 2020-10-21 17:42:00

GO连接MySQL

<p>Go语言没有提供官方的数据库驱动,所以要安装第三方函数库。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
    </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">database/sql</span><span style="color: rgba(128, 0, 0, 1)">"</span>
    <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    _ </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">github.com/go-sql-driver/mysql</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func main() {<br><br>   //数据库连接
    db,_:</span>=sql.Open(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mysql</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">root:root@(127.0.0.1:3306)/golang</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
   
    err :</span>=<span style="color: rgba(0, 0, 0, 1)">db.Ping()
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil{
      fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">数据库链接失败</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
    }<br>   </span></pre>
<pre><span>  defer db.Close()</span></pre>
<pre><span style="color: rgba(0, 0, 0, 1)"> <br>  //多行查询 </span></pre>
<pre>  rows,_:=db.Query("select * from stu")<br>  var id,name string<br>  for rows.Next(){<br>     rows.Scan(&amp;id,&amp;name)<br>   fmt.Println(id,name)<br>  }</pre>
<pre><span style="color: rgba(0, 0, 0, 1)">}</span></pre>
</div>
<h2 id="autoid-1-1-5">CRUD</h2>
<h3 id="autoid-1-2-0">建库建表</h3>
<p>我们先在MySQL中创建一个名为<code>sql_test</code>的数据库</p>
<pre class="line-numbers language-sql"><strong><code class="language-sql hljs"><span class="hljs-keyword">CREATE <span class="hljs-keyword">DATABASE sql_test;
</span></span></code></strong></pre>
<p>进入该数据库:</p>
<pre class="line-numbers language-sql"><code class="language-sql hljs"><span class="hljs-keyword">use sql_test;
</span></code></pre>
<p>执行以下命令创建一张用于测试的数据表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">CREATE TABLE `user` (
    `id` BIGINT(</span><span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(</span><span style="color: rgba(128, 0, 128, 1)">20</span>) DEFAULT <span style="color: rgba(128, 0, 0, 1)">''</span><span style="color: rgba(0, 0, 0, 1)">,
    `age` INT(</span><span style="color: rgba(128, 0, 128, 1)">11</span>) DEFAULT <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">0</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
    PRIMARY KEY(`id`)
)ENGINE</span>=InnoDB AUTO_INCREMENT=<span style="color: rgba(128, 0, 128, 1)">1</span> DEFAULT CHARSET=utf8mb4;</pre>
</div>
<h3 id="autoid-1-2-1">查询</h3>
<h4 id="单行查询">单行查询</h4>
<p>单行查询<code>db.QueryRow()</code>执行一次查询,并期望返回最多一行结果(即Row)。QueryRow总是返回非nil的值,直到返回值的Scan方法被调用时,才会返回被延迟的错误。(如:未找到结果)</p>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token keyword keyword-func"><span class="hljs-function"><span class="hljs-keyword">func <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(db <span class="token operator"><span class="hljs-function"><span class="hljs-params">*DB<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token function"><span class="hljs-function"><span class="hljs-title">QueryRow<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(query <span class="token builtin"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">string<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, args <span class="token operator"><span class="hljs-function"><span class="hljs-params">...<span class="token keyword keyword-interface"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">interface<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">{<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">}<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token operator"><span class="hljs-function">*<span class="hljs-title">Row</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code><br><br></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询单条数据示例</span>
<span style="color: rgba(0, 0, 0, 1)">func queryRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> u user
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放</span>
    err := db.QueryRow(sqlStr, <span style="color: rgba(128, 0, 128, 1)">1</span>).Scan(&amp;u.id, &amp;u.name, &amp;<span style="color: rgba(0, 0, 0, 1)">u.age)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">scan failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">id:%d name:%s age:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, u.id, u.name, u.age)
}</span></pre>
</div>
<h4 id="多行查询">多行查询</h4>
<p>多行查询<code>db.Query()</code>执行一次查询,返回多行结果(即Rows),一般用于执行select命令。参数args表示query中的占位参数。</p>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token keyword keyword-func"><span class="hljs-function"><span class="hljs-keyword">func <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(db <span class="token operator"><span class="hljs-function"><span class="hljs-params">*DB<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token function"><span class="hljs-function"><span class="hljs-title">Query<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(query <span class="token builtin"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">string<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, args <span class="token operator"><span class="hljs-function"><span class="hljs-params">...<span class="token keyword keyword-interface"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">interface<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">{<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">}<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(<span class="token operator"><span class="hljs-function"><span class="hljs-params">*Rows<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, <span class="token builtin"><span class="hljs-function"><span class="hljs-params">error<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">)
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>具体示例代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询多条数据示例</span>
<span style="color: rgba(0, 0, 0, 1)">func queryMultiRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where id &gt; ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    rows, err :</span>= db.Query(sqlStr, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 非常重要:关闭rows释放持有的数据库链接</span>
<span style="color: rgba(0, 0, 0, 1)">    defer rows.Close()

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 循环读取结果集中的数据</span>
    <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> rows.Next() {
      </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> u user
      err :</span>= rows.Scan(&amp;u.id, &amp;u.name, &amp;<span style="color: rgba(0, 0, 0, 1)">u.age)
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
            fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">scan failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
      }
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">id:%d name:%s age:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, u.id, u.name, u.age)
    }
}</span></pre>
</div>
<h3 id="autoid-1-2-2">插入数据</h3>
<p>插入、更新和删除操作都使用<span class="MathJax_Preview">方法。</span></p>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token keyword keyword-func"><span class="hljs-function"><span class="hljs-keyword">func <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(db <span class="token operator"><span class="hljs-function"><span class="hljs-params">*DB<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token function"><span class="hljs-function"><span class="hljs-title">Exec<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(query <span class="token builtin"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">string<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, args <span class="token operator"><span class="hljs-function"><span class="hljs-params">...<span class="token keyword keyword-interface"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">interface<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">{<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">}<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(Result<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, <span class="token builtin"><span class="hljs-function"><span class="hljs-params">error<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">)
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>Exec执行一次命令(包括查询、删除、更新、插入等),返回的Result是对已执行的SQL命令的总结。参数args表示query中的占位参数。</p>
<p>具体插入数据示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 插入数据</span>
<span style="color: rgba(0, 0, 0, 1)">func insertRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert into user(name, age) values (?,?)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">王五</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">38</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    theID, err :</span>= ret.LastInsertId() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 新插入数据的id</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get lastinsert ID failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert success, the id is %d.\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, theID)
}</span></pre>
</div>
<h3 id="autoid-1-2-3">更新数据</h3>
<p>具体更新数据示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 更新数据</span>
<span style="color: rgba(0, 0, 0, 1)">func updateRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update user set age=? where id = ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 128, 1)">39</span>, <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    n, err :</span>= ret.RowsAffected() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 操作影响的行数</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get RowsAffected failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update success, affected rows:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, n)
}</span></pre>
</div>
<h3 id="autoid-1-2-4">删除数据</h3>
<p>具体删除数据的示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 删除数据</span>
<span style="color: rgba(0, 0, 0, 1)">func deleteRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete from user where id = ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    n, err :</span>= ret.RowsAffected() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 操作影响的行数</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get RowsAffected failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete success, affected rows:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, n)
}</span></pre>
</div>
<p>&nbsp;</p>
<h2 id="autoid-1-2-5">MySQL预处理</h2>
<h3 id="autoid-1-3-0">什么是预处理?</h3>
<p>普通SQL语句执行过程:</p>
<ol>
<li>客户端对SQL语句进行占位符替换得到完整的SQL语句。</li>
<li>客户端发送完整SQL语句到MySQL服务端</li>
<li>MySQL服务端执行完整的SQL语句并将结果返回给客户端。</li>
</ol>
<p>预处理执行过程:</p>
<ol>
<li>把SQL语句分成两部分,命令部分与数据部分。</li>
<li>先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。</li>
<li>然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换。</li>
<li>MySQL服务端执行完整的SQL语句并将结果返回给客户端。</li>
</ol>
<h3 id="autoid-1-3-1">为什么要预处理?</h3>
<ol>
<li>优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本。</li>
<li>避免SQL注入问题。</li>
</ol>
<h3 id="autoid-1-3-2">Go实现MySQL预处理</h3>
<p>Go中的</p>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token keyword keyword-func"><span class="hljs-function"><span class="hljs-keyword">func <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(db <span class="token operator"><span class="hljs-function"><span class="hljs-params">*DB<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token function"><span class="hljs-function"><span class="hljs-title">Prepare<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(query <span class="token builtin"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">string<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">) <span class="token punctuation"><span class="hljs-function"><span class="hljs-params">(<span class="token operator"><span class="hljs-function"><span class="hljs-params">*Stmt<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">, <span class="token builtin"><span class="hljs-function"><span class="hljs-params">error<span class="token punctuation"><span class="hljs-function"><span class="hljs-params">)
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p><code>Prepare</code>方法会先将sql语句发送给MySQL服务端,返回一个准备好的状态用于之后的查询和命令。返回值可以同时执行多个查询和命令。</p>
<p>查询操作的预处理示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 预处理查询示例</span>
<span style="color: rgba(0, 0, 0, 1)">func prepareQueryDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where id &gt; ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    stmt, err :</span>=<span style="color: rgba(0, 0, 0, 1)"> db.Prepare(sqlStr)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">prepare failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    defer stmt.Close()
    rows, err :</span>= stmt.Query(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    defer rows.Close()
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 循环读取结果集中的数据</span>
    <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> rows.Next() {
      </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> u user
      err :</span>= rows.Scan(&amp;u.id, &amp;u.name, &amp;<span style="color: rgba(0, 0, 0, 1)">u.age)
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
            fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">scan failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
      }
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">id:%d name:%s age:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, u.id, u.name, u.age)
    }
}</span></pre>
</div>
<p>插入、更新和删除操作的预处理十分类似,这里以插入操作的预处理为例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 预处理插入示例</span>
<span style="color: rgba(0, 0, 0, 1)">func prepareInsertDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert into user(name, age) values (?,?)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    stmt, err :</span>=<span style="color: rgba(0, 0, 0, 1)"> db.Prepare(sqlStr)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">prepare failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    defer stmt.Close()
    _, err </span>= stmt.Exec(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王子</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    _, err </span>= stmt.Exec(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">沙河娜扎</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert success.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<h2 id="autoid-1-3-3">Go实现MySQL事务</h2>
<pre><span>事务相关方法
Go语言中使用以下三个方法实现MySQL中的事务操作。 开始事务

func (db *DB) Begin() (*<span>Tx, error)
提交事务

func (tx *<span>Tx) Commit() error
回滚事务

func (tx *<span>Tx) Rollback() error
事务示例
下面的代码演示了一个简单的事务操作,该事物操作能够确保两次更新操作要么同时成功要么同时失败,不会存在中间状态。</span></span></span></span></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 事务操作示例</span>
<span style="color: rgba(0, 0, 0, 1)">func transactionDemo() {
    tx, err :</span>= db.Begin() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开启事务</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> tx !=<span style="color: rgba(0, 0, 0, 1)"> nil {
            tx.Rollback() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 回滚</span>
<span style="color: rgba(0, 0, 0, 1)">      }
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">begin trans failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    sqlStr1 :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Update user set age=30 where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    _, err </span>= tx.Exec(sqlStr1, <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      tx.Rollback() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 回滚</span>
      fmt.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">exec sql1 failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    sqlStr2 :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Update user set age=40 where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    _, err </span>= tx.Exec(sqlStr2, <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      tx.Rollback() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 回滚</span>
      fmt.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">exec sql2 failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    err </span>= tx.Commit() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 提交事务</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      tx.Rollback() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 回滚</span>
      fmt.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">commit failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">exec trans success!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<h1 id="autoid-1-4-4">sqlx使用</h1>
<p>第三方库<code>sqlx</code>能够简化操作,提高开发效率。</p>
<h2 id="autoid-2-0-4">安装</h2>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token keyword keyword-go"><span class="hljs-keyword">go get github<span class="token punctuation">.com<span class="token operator">/jmoiron<span class="token operator">/sqlx
</span></span></span></span></span></code></pre>
<h2 id="autoid-2-1-0">基本使用</h2>
<h3 id="autoid-2-2-0">连接数据库</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> db *<span style="color: rgba(0, 0, 0, 1)">sqlx.DB

func initDB() (err error) {
    dsn :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user:password@tcp(127.0.0.1:3306)/test</span><span style="color: rgba(128, 0, 0, 1)">"</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 也可以使用MustConnect连接不成功就panic</span>
    db, err = sqlx.Connect(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mysql</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, dsn)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">connect DB failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    db.SetMaxOpenConns(</span><span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">)
    db.SetMaxIdleConns(</span><span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h3 id="autoid-2-2-1">查询</h3>
<p>查询单行数据示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询单条数据示例</span>
<span style="color: rgba(0, 0, 0, 1)">func queryRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> u user
    err :</span>= db.Get(&amp;u, sqlStr, <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">id:%d name:%s age:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, u.ID, u.Name, u.Age)
}</span></pre>
</div>
<p>查询多行数据示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询多条数据示例</span>
<span style="color: rgba(0, 0, 0, 1)">func queryMultiRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where id &gt; ?</span><span style="color: rgba(128, 0, 0, 1)">"</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> users []user
    err :</span>= db.Select(&amp;users, sqlStr, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">users:%#v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, users)
}</span></pre>
</div>
<h3 id="autoid-2-2-2">插入、更新和删除</h3>
<p>sqlx中的exec方法与原生sql中的exec使用基本一致:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 插入数据</span>
<span style="color: rgba(0, 0, 0, 1)">func insertRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert into user(name, age) values (?,?)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">沙河小王子</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">19</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    theID, err :</span>= ret.LastInsertId() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 新插入数据的id</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get lastinsert ID failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert success, the id is %d.\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, theID)
}</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 更新数据</span>
<span style="color: rgba(0, 0, 0, 1)">func updateRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update user set age=? where id = ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 128, 1)">39</span>, <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    n, err :</span>= ret.RowsAffected() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 操作影响的行数</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get RowsAffected failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update success, affected rows:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, n)
}</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 删除数据</span>
<span style="color: rgba(0, 0, 0, 1)">func deleteRowDemo() {
    sqlStr :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete from user where id = ?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    ret, err :</span>= db.Exec(sqlStr, <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    n, err :</span>= ret.RowsAffected() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 操作影响的行数</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">get RowsAffected failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete success, affected rows:%d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, n)
}</span></pre>
</div>
<h3 id="autoid-2-2-3">事务操作</h3>
<p>对于事务操作,我们可以使用<code>sqlx</code>中提供的<code>db.Beginx()</code>和<code>tx.MustExec()</code>方法来简化错误处理过程。示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">func transactionDemo() {
    tx, err :</span>= db.Beginx() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开启事务</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> tx !=<span style="color: rgba(0, 0, 0, 1)"> nil {
            tx.Rollback()
      }
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">begin trans failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    sqlStr1 :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Update user set age=40 where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    tx.MustExec(sqlStr1, </span><span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">)
    sqlStr2 :</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Update user set age=50 where id=?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    tx.MustExec(sqlStr2, </span><span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">)
    err </span>= tx.Commit() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 提交事务</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      tx.Rollback() </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 回滚</span>
      fmt.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">commit failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    fmt.Println(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">exec trans success!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<h1 id="autoid-2-2-4">注意事项</h1>
<h2 id="autoid-3-0-4">SQL中的占位符</h2>
<p>不同的数据库中,SQL语句使用的占位符语法不尽相同。</p>
<table>
<thead>
<tr><th>数据库</th><th>占位符语法</th></tr>
</thead>
<tbody>
<tr>
<td>MySQL</td>
<td><code>?</code></td>
</tr>
<tr>
<td>PostgreSQL</td>
<td><code>$1</code>,&nbsp;<code>$2</code>等</td>
</tr>
<tr>
<td>SQLite</td>
<td><code>?</code>&nbsp;和<code>$1</code></td>
</tr>
<tr>
<td>Oracle</td>
<td><code>:name</code></td>
</tr>
</tbody>
</table>
<h2 id="autoid-3-1-0">SQL注入</h2>
<p>我们任何时候都不应该自己拼接SQL语句!</p>
<p>这里我们演示一个自行拼接SQL语句的示例,编写一个根据name字段查询user表的函数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> sql注入示例</span>
func sqlInjectDemo(name <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">) {
    sqlStr :</span>= fmt.Sprintf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">select id, name, age from user where name='%s'</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, name)
    fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">SQL:%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, sqlStr)

    </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> users []user
    err :</span>= db.Select(&amp;<span style="color: rgba(0, 0, 0, 1)">users, sqlStr)
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">exec failed, err:%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, err)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
    }
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> _, u :=<span style="color: rgba(0, 0, 0, 1)"> range users {
      fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user:%#v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, u)
    }
}</span></pre>
</div>
<p>此时以下输入字符串都可以引发SQL注入问题:</p>
<pre class="line-numbers language-go"><code class="language-go hljs"><span class="token function">sqlInjectDemo<span class="token punctuation">(<span class="token string"><span class="hljs-string">"xxx' or 1=1#"<span class="token punctuation">)
<span class="token function">sqlInjectDemo<span class="token punctuation">(<span class="token string"><span class="hljs-string">"xxx' union select * from user #"<span class="token punctuation">)
<span class="token function">sqlInjectDemo<span class="token punctuation">(<span class="token string"><span class="hljs-string">"xxx' and (select count(*) from user) &lt;10 #"<span class="token punctuation">)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre><br><br>
来源:https://www.cnblogs.com/peteremperor/p/13853759.html
頁: [1]
查看完整版本: GO连接MySQL