一文学会Go语言数据库操作
sicoly
8年前
<p>对许多 Web 应用程序而言,数据库都是其核心所在。数据库几乎可以用来存储想查询和修改的任何信息,比如用户信息、产品目录或者新闻列表等。</p> <p>数据库是Web编程不可或缺的主题。这里我们就来看一下如何用 Go 语言操作不同的数据库。</p> <h2>database/sql 接口</h2> <p>Go 语言不同于 PHP,它没有官方提供任何数据库驱动,而是为开发者定义了一组标准接口。提供数据库服务的开发者,可以实现这组接口,以为特定的数据提供驱动。而数据库的使用者,也可以通过这组接口方便地访问数据库,甚至在适当的时候,以非常小的代价迁移数据库。</p> <p>通常我们在以类似如下的方式导入数据库驱动模块时:</p> <pre> <code class="language-sql">import _ "github.com/Go-SQL-Driver/MySQL" </code></pre> <p>上面的 import 语句中的下划线表示,我们要导入这个模块,但不会直接使用其中的符号。但导入的时候,会执行模块的初始化代码,也就是其中定义的 init() 函数,在这个函数中数据库驱动会自动将其自身注册进 Go 的 database/sql 框架中,后面我们就可以方便地通过这个接口来访问对应得数据了。</p> <p>关于这组接口的详细内容,可以参考 <a href="/misc/goto?guid=4959738996981675800" rel="nofollow,noindex">官方文档</a> 。</p> <h2>MySQL</h2> <p>目前网上流行的网站架构方式是 LAMP,其中的 M 即为 MySQL。作为数据库,MySQL 以免费、开源、使用方便为优势而成为了许多Web开发的后端数据库存储引擎。</p> <h2>MySQL 安装</h2> <p>首先我们需要安装 MySQL,这可以通过如下的命令来完成:</p> <pre> <code class="language-sql">$ sudo apt install mysql-server $ sudo apt-get install mysql-client $ mysql_secure_installation </code></pre> <p>安装之后,通过如下命令可以查看 MySQL 服务器占用的端口:</p> <pre> <code class="language-sql">$ sudo lsof -i -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME . . . . . . mysqld 17860 mysql 20u IPv4 136588 0t0 TCP localhost:3306 (LISTEN) </code></pre> <p>可以看到 MySQL 服务器在 TCP 的 <strong> <em>3306</em> </strong> 端口监听请求。</p> <h2>新MySQL建用户</h2> <p>安装好了 MySQL 之后,我们还需要创建用户,以便于后面在代码里使用。创建用户的方法如下:</p> <pre> <code class="language-sql">## 登录MYSQL $ mysql -u root -p Enter password: ## 创建用户 mysql> CREATE USER 'hanpfei'@'localhost' IDENTIFIED BY 'hanpfei'; ## 刷新系统权限表 mysql>flush privileges; </code></pre> <p>这样就创建了一个名为 hanpfei ,密码为 hanpfei 的用户。</p> <p>然后登录一下。</p> <pre> <code class="language-sql">mysql> exit; $ mysql -u hanpfei -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 11 Server version: 5.7.17-0ubuntu0.16.04.1 (Ubuntu) . . . . . . mysql> </code></pre> <h2>创建数据库并为用户授权</h2> <p>登录MYSQL(有ROOT权限)。我里我以 ROOT 身份登录.</p> <pre> <code class="language-sql">$ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 12 Server version: 5.7.17-0ubuntu0.16.04.1 (Ubuntu) </code></pre> <p>为用户创建一个数据库 ( staff_info_db )</p> <pre> <code class="language-sql">mysql>create database staff_info_db; </code></pre> <p>授权 hanpfei 用户拥有 staff_info_db 数据库的所有权限。</p> <pre> <code class="language-sql">mysql>grant all privileges on staff_info_db.* to hanpfei@localhost identified by 'hanpfei'; </code></pre> <p>刷新系统权限表</p> <pre> <code class="language-sql">mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) </code></pre> <h2>创建表</h2> <p>有了数据库,接下来就是创建表了。建表语句如下:</p> <pre> <code class="language-sql">CREATE TABLE `userinfo1` ( `uid` INT(10) NOT NULL AUTO_INCREMENT, `username` VARCHAR(64) NULL DEFAULT NULL, `departname` VARCHAR(64) NULL DEFAULT NULL, `created` DATE NULL DEFAULT NULL, PRIMARY KEY (`uid`) ); CREATE TABLE `userdetail` ( `uid` INT(10) NOT NULL DEFAULT '0', `intro` TEXT NULL, `profile` TEXT NULL, PRIMARY KEY (`uid`) ); </code></pre> <p>具体的建表可以通过如下得命令来完成:</p> <pre> <code class="language-sql">$ mysql -u hanpfei -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 18 Server version: 5.7.17-0ubuntu0.16.04.1 (Ubuntu) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use staff_info_db; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> CREATE TABLE `userinfo` ( -> `uid` INT(10) NOT NULL AUTO_INCREMENT, -> `username` VARCHAR(64) NULL DEFAULT NULL, -> `departname` VARCHAR(64) NULL DEFAULT NULL, -> `created` DATE NULL DEFAULT NULL, -> PRIMARY KEY (`uid`) -> ); Query OK, 0 rows affected (0.80 sec) mysql> CREATE TABLE `userdetail` ( -> `uid` INT(10) NOT NULL DEFAULT '0', -> `intro` TEXT NULL, -> `profile` TEXT NULL, -> PRIMARY KEY (`uid`) -> ); Query OK, 0 rows affected (0.80 sec) mysql> exit Bye </code></pre> <p>这样我们需要的表就建好了。</p> <h2>用 Go 语言访问 MySQL</h2> <p>安装好了数据库,并创建了适当的用户、数据库以及数据库表之后,我们就可以开始用 Go 语言访问 MySQL了。然而,在实际写代码之前,还要先下载对应的驱动。Go 语言中支持 MySQL 的驱动目前比较多,我们以支持 Go 语言标准 database/sql 接口的 github.com/Go-SQL-Driver/MySQL 为例来看。我们先要下载这个包:</p> <pre> <code class="language-sql">$ go get github.com/Go-SQL-Driver/MySQL </code></pre> <p>然后来看如何使用 database/sql 接口对数据库表进行增删改查操作:</p> <pre> <code class="language-sql">package main import ( _ "github.com/Go-SQL-Driver/MySQL" "fmt" "database/sql" ) func checkErr(err error) { if err != nil { panic(err) } } func mysqlTest() { db, err := sql.Open("mysql", "hanpfei:hanpfei@/staff_info_db?charset=utf8") checkErr(err) defer db.Close() // Insert stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?") checkErr(err) res, err := stmt.Exec("hanpfei", "R&D Department", "2016-05-23") checkErr(err) id, err := res.LastInsertId() checkErr(err) fmt.Println(id) // Update stmt, err = db.Prepare("UPDATE userinfo SET username=? where uid=?") checkErr(err) res, err = stmt.Exec("hanpfeiupdate", id) checkErr(err) affect, err := res.RowsAffected() checkErr(err) fmt.Println(affect) // Query rows, err := db.Query("SELECT * FROM userinfo") checkErr(err) for rows.Next() { var uid int var username string var department string var created string err = rows.Scan(&uid, &username, &department, & created) checkErr(err) fmt.Println(uid) fmt.Println(username) fmt.Println(department) fmt.Println(created) } // Delete data stmt, err = db.Prepare("DELETE from userinfo where uid=?") checkErr(err) res, err = stmt.Exec(id) checkErr(err) affect, err = res.RowsAffected() checkErr(err) fmt.Println(affect) checkErr(err) } func main() { mysqlTest() } </code></pre> <p>通过以上代码,可以看出来 Go 语言操作 MySQL 数据库还是非常方便的。关于这个数据库驱动的用法更详细的信息,可以参考其 <a href="/misc/goto?guid=4959738997066144011" rel="nofollow,noindex">官方文档</a> 。</p> <h2>SQLite3</h2> <p>SQLite 是一个开源的嵌入式系统的关系型数据库,它是实现自包容、零配置且支持事务的 SQL 数据库引擎。其特点是高度便携、结构紧凑、高效且可靠。与其它许多数据库相比,SQLite 的安装运行都非常简单。大多数情况下,只要确保 SQLite 的二进制文件存在,即可创建和访问数据库。</p> <p>可以通过如下的命令来安装 SQLite:</p> <pre> <code class="language-sql">$ sudo apt-get install libsqlite3-0 libsqlite3-dev </code></pre> <p>SQLite 的命令行工具可装可不装,不影响我们通过代码操作 SQLite 数据库。</p> <p>同样我们需要选择一款 SQLite 驱动。Go 语言支持 SQLite 的驱动也比较多,但好多都不支持 database/sql 接口。这里我们选择支持 database/sql 接口的 github.com/mattn/go-sqlite3 。</p> <p>在开始写代码前,要先安装这个驱动:</p> <pre> <code class="language-sql">$ go get github.com/mattn/go-sqlite3 </code></pre> <p>建表的语句如下:</p> <pre> <code class="language-sql">CREATE TABLE `userinfo` ( `uid` INTEGER PRIMARY KEY AUTOINCREMENT, `username` VARCHAR(64) NULL, `departname` VARCHAR(64) NULL, `created` DATE NULL ); CREATE TABLE `userdetail` ( `uid` INT(10) NULL, `intro` TEXT NULL, `profile` TEXT NULL, PRIMARY KEY (`uid`) ); </code></pre> <p>不过我们同样通过代码来完成建表了。然后来看在 Go 语言中,具体如何操作 SQLite :</p> <pre> <code class="language-sql">package main import ( _ "github.com/mattn/go-sqlite3" "database/sql" "fmt" ) func checkErr(err error) { if err != nil { panic(err) } } func testOperationForSqlite3(db *sql.DB) { // Insert stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, created) values(?,?,?)") checkErr(err) res, err := stmt.Exec("hanpfei", "R&D Department", "2016-05-23") checkErr(err) id, err := res.LastInsertId() checkErr(err) fmt.Println(id) // Update stmt, err = db.Prepare("UPDATE userinfo SET username=? where uid=?") checkErr(err) res, err = stmt.Exec("hanpfeiupdate", id) checkErr(err) affect, err := res.RowsAffected() checkErr(err) fmt.Println(affect) // Query rows, err := db.Query("SELECT * FROM userinfo") checkErr(err) for rows.Next() { var uid int var username string var department string var created string err = rows.Scan(&uid, &username, &department, & created) checkErr(err) fmt.Println(uid) fmt.Println(username) fmt.Println(department) fmt.Println(created) } // Delete data stmt, err = db.Prepare("DELETE from userinfo where uid=?") checkErr(err) res, err = stmt.Exec(id) checkErr(err) affect, err = res.RowsAffected() checkErr(err) fmt.Println(affect) checkErr(err) } func createTableForSqlite3(db *sql.DB) { createTableCommand := "CREATE TABLE userinfo (uid INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(64) NULL, " + "departname VARCHAR(64) NULL, created DATE NULL);" stmt, err := db.Prepare(createTableCommand) checkErr(err) _, err = stmt.Exec() checkErr(err) createTableCommand = "CREATE TABLE userdetail (uid INT(10) NULL, intro TEXT NULL, profile TEXT NULL, PRIMARY KEY (uid));" stmt, err = db.Prepare(createTableCommand) checkErr(err) _, err = stmt.Exec() checkErr(err) } func sqlite3Test() { db, err := sql.Open("sqlite3", "./foo.db") checkErr(err) defer db.Close() createTableForSqlite3(db) testOperationForSqlite3(db) } func main() { sqlite3Test() } </code></pre> <p>执行上面的代码,将看到如下的输出:</p> <pre> <code class="language-sql">/usr/lib/go/bin/go run /home/hanpfei0306/IdeaProjects/HelloGo/Sqlite3.go 1 1 1 hanpfeiupdate R&D Department 2016-05-23T00:00:00Z 1 Process finished with exit code 0 </code></pre> <p>我们可以看到,上面操作 SQLite 数据库的代码,和前面操作 MySQL 数据库的代码几乎一模一样。仅有的改变是导入的驱动变了,然后调用 sql,Open() 打开数据库驱动的方式不同。</p> <h2>PostgreSQL</h2> <p>PostgreSQL 是一个开源的自由的对象-关系数据库服务器,它以灵活的 BSD-Style 许可发行。相对于其它许多的开源数据库系统(如 MySQL 和 Firebird)和商业数据库系统(如 Oracle 和 MS SQL Server),它为我们提供了另外的一种选择。</p> <p>PostgreSQL 相对于 MySQL 而言更加庞大,因为它本是为替代 Oracle 而设计。</p> <p>这里我们就来看一下如何用 Go 语言操作 PostgreSQL。</p> <h2>安装</h2> <p>我们首先要安装 PostgreSQL 服务器。使用如下命令,会自动安装最新版,这里为 9.5 :</p> <pre> <code class="language-sql">sudo apt-get install postgresql </code></pre> <p>安装完成后,默认会:</p> <p>(1)创建名为 “postgres” 的Linux用户</p> <p>(2)创建名为 “postgres”、不带密码的默认数据库账号作为数据库管理员</p> <p>(3)创建名为 “postgres” 的表</p> <p>安装完成后的一些默认信息如下:</p> <pre> <code class="language-sql">config /etc/postgresql/9.5/main data /var/lib/postgresql/9.5/main locale en_US.UTF-8 socket /var/run/postgresql port 5432 </code></pre> <p>通过 lsof -i 命令我们可以查看 PostgreSQL 服务器占用的端口,并确认其在正常运行:</p> <pre> <code class="language-sql">$ sudo lsof -i -P . . . . . . postgres 24581 postgres 6u IPv6284716 0t0 TCP localhost:5432 (LISTEN) postgres 24581 postgres 7u IPv4284717 0t0 TCP localhost:5432 (LISTEN) postgres 24581 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 postgres 24583 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 postgres 24584 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 postgres 24585 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 postgres 24586 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 postgres 24587 postgres 11u IPv6279448 0t0 UDP localhost:42368->localhost:42368 </code></pre> <p>可以看到 PostgreSQL 服务器在 TCP 的 <strong> <em>5432</em> </strong> 端口上监听请求,并开启了多个进程来监听。</p> <h2>配置</h2> <p>安装完后会有 PostgreSQL 的客户端 psql 可以用,通过 sudo -u postgres psql 进入,提示符变成 postgres=# :</p> <pre> <code class="language-sql">$ sudo -u postgres psql psql (9.5.6) Type "help" for help. postgres=# </code></pre> <p>在这里可以执行 SQL 语句和 psql 的基本命令。</p> <h2>新建 PostgreSQL用户</h2> <p>我们可以通过如下的命令</p> <pre> <code class="language-sql">postgres=# CREATE USER hanpfei PASSWORD 'hanpfei' CREATEDB; CREATE ROLE </code></pre> <p>通过 \du 可以查看当前已经存在的用户列表:</p> <pre> <code class="language-sql">postgres=# \du List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- hanpfei | Create DB | {} postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} </code></pre> <p>此时我们以新创建的用户登录PostgreSQL,会报出如下得error:</p> <pre> <code class="language-sql">$ sudo -u postgres psql -U hanpfei psql: FATAL: Peer authentication failed for user "hanpfei" </code></pre> <p>我们可以通过修改 pg_hba.conf 文件来解决这个问题:</p> <pre> <code class="language-sql">$ sudo gedit /etc/postgresql/9.5/main/pg_hba.conf </code></pre> <p>将其中 <strong> <em> 除 postgres 用户外 </em> </strong> 的所有用户的 METHOD 都从 peer 或 ident 改为 md5 或 trust 。</p> <p>修改完毕,保存退出。</p> <p>然后执行如下命令重新加载配置:</p> <pre> <code class="language-sql">$ /etc/init.d/postgresql reload </code></pre> <p>再次尝试用新创建的用户的登录 PostgreSQL 时报出了新的 error:</p> <pre> <code class="language-sql">$ sudo -u postgres psql -U hanpfei Password for user hanpfei: psql: FATAL: database "hanpfei" does not exist </code></pre> <p>提示用户的数据库不存在。我们还需要再次登录 postgres 用户,为我们的新用户创建数据库:</p> <pre> <code class="language-sql">$ sudo -u postgres psql psql (9.5.6) Type "help" for help. postgres=# create database hanpfei; CREATE DATABASE postgres=# \q </code></pre> <p>然后就可以以新用户登录了:</p> <pre> <code class="language-sql">$ sudo -u postgres psql -U hanpfei [sudo] hanpfei0306 的密码: Password for user hanpfei: psql (9.5.6) Type "help" for help. hanpfei=> </code></pre> <p>这里我们需要输入两次密码,一次是当前 Linux 用户的用户密码,用来执行 sudo,另一次是数据库的用户的密码,用来登录数据库。</p> <p>接着我们创建一个新的应用数据库,并选择它作为我们当前使用的数据库,这可以通过 \c 命令来实现:</p> <pre> <code class="language-sql">hanpfei=> \l List of databases Name |Owner|Encoding|Collate|Ctype|Access privileges ---------------+----------+----------+-------------+-------------+----------------------- hanpfei |postgres|UTF8|zh_CN.UTF-8|zh_CN.UTF-8| postgres |postgres|UTF8|zh_CN.UTF-8|zh_CN.UTF-8| staff_info_db |hanpfei|UTF8|zh_CN.UTF-8|zh_CN.UTF-8| template0 |postgres|UTF8|zh_CN.UTF-8|zh_CN.UTF-8|=c/postgres + |||||postgres=CTc/postgres template1 |postgres|UTF8|zh_CN.UTF-8|zh_CN.UTF-8|=c/postgres + |||||postgres=CTc/postgres (5 rows) hanpfei=> create database staff_info_db; hanpfei=> \c staff_info_db; You are now connected to database "staff_info_db" as user "hanpfei". staff_info_db=> </code></pre> <p>上面的 \l 是用来列出当前已创建的所有数据库的。注意我们切换了数据库之后,命令输入提示字符串也变为了新数据库的名字。</p> <p>然后创建表。建表语句如下:</p> <pre> <code class="language-sql">CREATE TABLE userinfo ( uid serial NOT NULL, username character varying(100) NOT NULL, departname character varying(100) NOT NULL, created date, CONSTRAINT userinfo_pkey PRIMARY KEY (uid) ) WITH (OIDS=FALSE); CREATE TABLE userdetail ( uid integer, intro character varying(100), profile character varying(100) ) WITH (OIDS=FALSE); </code></pre> <p>具体命令则是:</p> <pre> <code class="language-sql">staff_info_db=> CREATE TABLE userinfo ( staff_info_db(> uid serial NOT NULL, staff_info_db(> username character varying(100) NOT NULL, staff_info_db(> departname character varying(100) NOT NULL, staff_info_db(> created date, staff_info_db(> CONSTRAINT userinfo_pkey PRIMARY KEY (uid) staff_info_db(> ) staff_info_db-> WITH (OIDS=FALSE); CREATE TABLE staff_info_db=> CREATE TABLE userdetail ( staff_info_db(> uid integer, staff_info_db(> intro character varying(100), staff_info_db(> profile character varying(100) staff_info_db(> ) staff_info_db-> WITH (OIDS=FALSE); CREATE TABLE staff_info_db=> </code></pre> <h2>权限</h2> <p>创建的表还可以赋予其它用户完全的权限,比如,以 postgres 用户创建的表的完全的权限赋予新用户:</p> <pre> <code class="language-sql">postgres=# GRANT ALL ON userinfo TO hanpfei; postgres=# GRANT ALL ON userinfo TO userdetail; </code></pre> <h2>使用 Go 语言操作 PostgreSQL</h2> <p>同样我们需要先找个驱动。Go 语言的 PostgreSQL 驱动也很多。这里我们选用支持 database/sql 接口的驱动 github.com/lib/pq ,这个项目由 github.com/bmizerany/pq 迁移而来,而后者目前已经废弃。我们还是要先安装:</p> <pre> <code class="language-sql">$ go get github.com/lib/pq </code></pre> <p>然后用 Go 语言访问 PostgreSQL:</p> <pre> <code class="language-sql">package main import ( _ "github.com/lib/pq" "fmt" "database/sql" ) func checkErr(err error) { if err != nil { panic(err) } } func testOperationForPostgreSQL(db *sql.DB) { // Insert stmt, err := db.Prepare("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) RETURNING uid") checkErr(err) res, err := stmt.Exec("hanpfei", "R_D_Department", "2016-05-23") checkErr(err) // id, err := res.LastInsertId() // checkErr(err) fmt.Println(res) // Update stmt, err = db.Prepare("UPDATE userinfo SET username=$1 where uid=$2") checkErr(err) res, err = stmt.Exec("hanpfeiupdate", 1) checkErr(err) affect, err := res.RowsAffected() checkErr(err) fmt.Println(affect) // Query rows, err := db.Query("SELECT * FROM userinfo") checkErr(err) for rows.Next() { var uid int var username string var department string var created string err = rows.Scan(&uid, &username, &department, & created) checkErr(err) fmt.Println(uid) fmt.Println(username) fmt.Println(department) fmt.Println(created) } // Delete data stmt, err = db.Prepare("DELETE from userinfo where uid=$1") checkErr(err) res, err = stmt.Exec(1) checkErr(err) affect, err = res.RowsAffected() checkErr(err) fmt.Println(affect) checkErr(err) } func postgreSqlTest() { db, err := sql.Open("postgres", "user=hanpfei password=hanpfei dbname=staff_info_db sslmode=disable") checkErr(err) defer db.Close() testOperationForPostgreSQL(db) } func main() { postgreSqlTest() } </code></pre> <p>从上面的代码中可以看到,PostgreSQL 是通过 “$1,$2”这种方式来占位要传入的参数的,而不是 MySQL 中的 “?” 另外在 sql.Open() 中的 dsn 信息的格式也与 MySQL 不同,因而在使用时需要注意。</p> <p>此外, PostgreSQL 不支持 LastInsertId() 函数,因为它内部没有实现类似 MySQL 的自增 ID 返回。其它的代码则几乎一模一样。</p> <h2>NoSQL 数据库</h2> <p>NoSQL (Not only SQL),指的是非关系型数据库。随着 Web 2.0 的兴起,传统的关系型数据库在应付新应用,特别是超大规模和高并发得 SNS 型 Web 2.0 纯动态网站时已经显得力不从心,暴露了很多难以客服得问题,而非关系型数据库则由于其自身的有点,而得到迅速得发展。</p> <p>在看了上面的几种 SQL 数据库之后,接下来我们将学习用 Go 语言操作几种 NoSQL 数据库,主要是 Redis 和 MongoDB。</p> <h2>Redis</h2> <p>Redis 是一个开源的(BSD 许可),基于内存的数据结构存储产品,它可以被用作数据库,缓存和消息代理。它支持的数据结构非常多,如 string(字符串),hash(哈希),list(列表),set(集合),带有范围查询的sorted set(有序集合),bitmap(位图),超文本和具有半径查询的地理空间索引。Redis具有内置复制,Lua脚本,LRU驱逐,事务和不同级别的磁盘持久性,并通过Redis Sentinel提供高可用性,并通过Redis Cluster进行自动分区。</p> <p>Redis 是一个超高性能的 key-value 数据库。Redis 的出现,很大程度补偿了memcached 这类 key-value 存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。</p> <p>这里我们就来看一下如何用 Go 语言操作Redis。</p> <h2>Redis 安装</h2> <p>使用如下命令,会自动安装最新版</p> <pre> <code class="language-sql">$ sudo apt-get install redis-server redis-tools </code></pre> <p>通过 lsof -i 命令我们可以查看 Redis 服务器占用的端口。</p> <pre> <code class="language-sql">$ sudo lsof -i -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME . . . . . . redis-ser 2977 redis 4u IPv4 507101 0t0 TCP localhost:6379 (LISTEN) </code></pre> <p>可以看到 Redis 服务器在 TCP 的 <strong> <em>6379</em> </strong> 端口监听请求。</p> <p>Redis 还提供了功能强大的命令行工具</p> <pre> <code class="language-sql">$ redis-cli 127.0.0.1:6379> help redis-cli 3.0.6 Type: "help @<group>" to get a list of commands in <group> "help <command>" for help on <command> "help <tab>" to get a list of possible help topics "quit" to exit </code></pre> <h2>Go 程序访问 Redis</h2> <p>Go 语言的 Redis 客户端驱动还是很多的,具体可以通过 Redis 的 Client 页 找到它们。当前还处于比较活跃的状态,也就是近 6 个月官方 repo 有过更新的驱动如下:</p> <pre> <code class="language-sql">https://github.com/go-redis/redis https://github.com/keimoon/gore https://github.com/gosexy/redis https://github.com/tideland/golib https://github.com/garyburd/redigo https://github.com/mediocregopher/radix.v2 </code></pre> <p>其中最后两个,是目前 Redis 官方推荐使用的 Go 驱动。这里我们以最后一个为例,来看要如何在 Go 代码里操作 Redis。然而,在开始之前,我们还是要先安装相应的包:</p> <pre> <code class="language-sql">$ go get github.com/mediocregopher/radix.v2/redis </code></pre> <p>接着来看具体如何通过 Go 语言访问 Redis:</p> <pre> <code class="language-sql">package main import ( "fmt" "github.com/mediocregopher/radix.v2/redis" ) func checkErr(err error) { if err != nil { panic(err) } } func testRedisWithRadix() { client, err := redis.Dial("tcp", "localhost:6379") checkErr(err) err = client.Cmd("SET", "a", "hello").Err checkErr(err) val, err := client.Cmd("GET", "a").Str() checkErr(err) fmt.Println("Redis val:") fmt.Println(string(val)) err = client.Cmd("DEL", "a").Err checkErr(err) // list operation vals := []string{"a", "b", "c", "d", "e"} for _, v := range vals { err = client.Cmd("RPUSH", "l", v).Err checkErr(err) } dbvals, err := client.Cmd("LRANGE", "l", 0, 4).List() checkErr(err) for i, v := range dbvals { fmt.Println(i, ":", string(v)) } err = client.Cmd("DEL", "l").Err checkErr(err) } func main() { testRedisWithRadix() } </code></pre> <p>运行上面代码,可以看到如下的输出:</p> <pre> <code class="language-sql">$ /usr/lib/go/bin/go run /home/hanpfei0306/IdeaProjects/HelloGo/Redis.go Redis val: hello 0 : a 1 : b 2 : c 3 : d 4 : e Process finished with exit code 0 </code></pre> <p>我们可以看到,操作 Redis 非常方便,大多只要用 client 命令即可。关于 Radix 用法的更多详细内容,可以参考其 <a href="/misc/goto?guid=4959738997149201215" rel="nofollow,noindex">官方文档</a> 。</p> <h2>MongoDB</h2> <p>MongoDB 是一个高性能功能强大而流行的分布式文档存储 NoSQL (Not Only SQL) 数据库产品。它是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。</p> <p>下面我们来看一下如何通过 Go 语言操作 MongoDB。</p> <h2>MongoDB 安装</h2> <p>首先需要安装 MongoDB。使用如下命令,会自动安装最新版 MongoDB,这里是 2.6.10 版。</p> <pre> <code class="language-sql">$ sudo apt-get install mongodb mongodb-clients mongodb-server </code></pre> <p>通过 lsof -i 命令我们可以查看 MongoDB 服务器占用的端口,并确认 MongoDB 服务器的正常运行。</p> <pre> <code class="language-sql"> sudo lsof -i -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME . . . . . . mongod 7838 mongodb 8u IPv4 536811 0t0 TCP localhost:27017 (LISTEN) </code></pre> <p>可以看到 MongoDB 服务器在 TCP 的 <strong> <em>27017</em> </strong> 端口监听请求。</p> <h2>创建数据库</h2> <p>安装了 MongoDB 服务器之后,我们还要创建数据库,以备后面在代码里面用。我们可以通过 MongoDB 的 shell 版本,使用 use 命令创建数据库:</p> <pre> <code class="language-sql">$ mongo MongoDB shell version: 2.6.10 connecting to: test Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ Questions? Try the support group http://groups.google.com/group/mongodb-user > use people_info switched to db people_info </code></pre> <p>use 命令在 MySQL 中用于选择已经创建好的数据库,而在 MongoDB 中则会自动创建当前还不存在的数据库。</p> <h2>Go 程序访问 MongoDB</h2> <p>在开始编写 Go 代码访问 MongoDB 数据库之前,我们还要先下载 MongoDB 的Go语言驱动。在 MongoDB 的 官方 Drivers主页 可以找到可用的 Go 语言驱动。当前官方推荐的只有开源社区支持的 mgo 驱动。 mgo 主页 。mgo 的 GitHub 主页 。通过 go get 命令安装我们需要的两个 mgo Go 包:</p> <pre> <code class="language-sql">$ go get gopkg.in/mgo.v2 $ go get gopkg.in/mgo.v2/bson </code></pre> <p>接着来看具体如何通过 Go 语言操作 MongoDB。</p> <pre> <code class="language-sql">package main import ( "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" "fmt" ) type Person struct { Name string Phone string } funccheckErr(err error) { if err != nil { panic(err) } } functestMongoDB() { session, err := mgo.Dial("localhost") checkErr(err) defer session.Close() session.SetMode(mgo.Monotonic, true) c := session.DB("people_info").C("people") err = c.Insert(&Person{"Ale", "+55 53 8116 9639"}, &Person{"Cla", "+55 53 8402 8510"}) checkErr(err) result := Person{} err = c.Find(bson.M{"name": "Ale"}).One(&result) checkErr(err) fmt.Println("Phone:", result.Phone) } funcmain() { testMongoDB() } </code></pre> <p>操作与许多 SQL数据库的 ORM 库提供的很相似,可以直接操作对象。</p> <p> </p> <p>来自:https://www.wolfcstech.com/2017/02/26/一文学会Go语言数据库操作/</p> <p> </p>