Go言語 + webFramework revelで、MYSQLを使用する


##参考サイト
https://github.com/golang/go/wiki/SQLDrivers
http://mix3.github.io/blog/2014/03/08/20140308/



##mysqlのインストール

サーバは、`Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-24-generic x86_64)`どすえ。

```
sudo apt-get install mysql-server
```

インストール中に、mysqlのrootパスワードを聞いてくるので、
`vagrant`と入力。(vagrantで立ち上げているサーバなので)

##接続してみる。

```
$ mysql -u root -p 
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 42
Server version: 5.5.40-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, 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>
```

```
mysql> status
--------------
mysql  Ver 14.14 Distrib 5.5.40, for debian-linux-gnu (x86_64) using readline 6.3

Connection id:		42
Current database:
Current user:		root@localhost
SSL:			Not in use
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server version:		5.5.40-0ubuntu0.14.04.1 (Ubuntu)
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	latin1
Db     characterset:	latin1
Client characterset:	utf8
Conn.  characterset:	utf8
UNIX socket:		/var/run/mysqld/mysqld.sock
Uptime:			2 min 0 sec

Threads: 1  Questions: 583  Slow queries: 0  Opens: 421  Flush tables: 1  Open tables: 41  Queries per second avg: 4.858
--------------

mysql>
```

よしよし。

##データベースの作成

```mysql
mysql> create database GODB character set utf8;
Query OK, 1 row affected (0.00 sec)
```

```mysql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| GODB               |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)

```

```mysql
mysql> SHOW CREATE DATABASE GODB;
+----------+---------------------------------------------------------------+
| Database | Create Database                                               |
+----------+---------------------------------------------------------------+
| GODB     | CREATE DATABASE `GODB` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+---------------------------------------------------------------+
1 row in set (0.00 sec)
```

##テーブルの作成

```mysql
mysql> use GODB
Database changed
```

```mysql
mysql> show tables;
Empty set (0.00 sec)
```

```
mysql> CREATE TABLE users
    -> (
    -> id INT(11) NOT NULL AUTO_INCREMENT,
    -> name VARCHAR(64),
    -> age INT(11),
    -> PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql>
```

```mysql
show tables;
+----------------+
| Tables_in_GODB |
+----------------+
| users           |
+----------------+
1 row in set (0.00 sec)
```

```mysql
mysql> DESC users;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(64) | YES  |     | NULL    |                |
| age   | int(11)     | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql>
```

```mysql
mysql> select * from users;
Empty set (0.00 sec)

mysql>
```

ふう。一通り、完了。
ほんとは、goからテーブルまでつくらないとねー。

##revel側のデータベース接続設定

revelにはORMは付属していないので、
自分で導入する必要がある。gorpとgormで悩んだけど、
とりあえずは、gormを使ってみる。

###インストール

まず、ORMをインストール

```sh
//$ go get github.com/coopernurse/gorp
$ go get -u github.com/jinzhu/gorm
```

次に、mysqlドライバーをインストール

```sh
$ go get github.com/go-sql-driver/mysql
```

###使ってみる。

データベース接続情報を`src/myapp/conf/app.conf`に記載しておく。
なにを書いているかはある程度わかるでしょ？

```
db.user = root
db.password = vagrant
db.host = 192.168.1.3
db.port = 3306
db.name = GODB
db.protocol = tcp
```

次にコード。ほんとはモデルは`Model/`配下において使うべきだけど、
テストなので、`myapp/app/controllers/app.go`に直で書いてみる。

まずは、インポート。

```go
import (
    "github.com/revel/revel"
    _ "github.com/go-sql-driver/mysql"　// 新規追加
    "github.com/jinzhu/gorm"　// 新規追加
    "strings"　// 新規追加
    "fmt"　// 新規追加
)
```

ユーザ構造体は、以下のように書き換えた。

```go
type User struct {
    Id int64 `json:"id"`
    Name string `json:"name"`
    Age int32 `json:"age"`
}
```

次に、configから情報を取り出して、文字列整形してくれる関数を
参考サイトから取り出してそのままコピペ。

https://github.com/jinzhu/gorm
https://rclayton.silvrback.com/revel-gorp-and-mysql →これがいい。

```go
func getParamString(param string, defaultValue string) string {
    p, found := revel.Config.String(param)
    if !found {
        if defaultValue == "" {
            revel.ERROR.Fatal("Cound not find parameter: " + param)
        } else {
            return defaultValue
        }
    }
    return p
}

func getConnectionString() string {
    host := getParamString("db.host", "")
    port := getParamString("db.port", "3306")
    user := getParamString("db.user", "")
    pass := getParamString("db.password", "")
    dbname := getParamString("db.name", "auction")
    protocol := getParamString("db.protocol", "tcp")
    dbargs := getParamString("dbargs", " ")

    if strings.Trim(dbargs, " ") != "" {
        dbargs = "?" + dbargs
    } else {
        dbargs = ""
    }
    return fmt.Sprintf("%s:%s@%s([%s]:%s)/%s%s",-
        user, pass, protocol, host, port, dbname, dbargs)
}
```

で、使う。

```
func (c App) Index() revel.Result {
    //return c.Render()

    // 接続するための情報文字列を作る
    connectionString := getConnectionString()

　　 // DB接続
    db, err := gorm.Open("mysql", connectionString)
    if err != nil {
        revel.ERROR.Println("FATAL", err)
        panic( err )
    }
    db.DB()

    // ユーザ情報の作成
    user := &User{Name: "go tarou", Age: 34}

    // レコードの追加
    db.Create(user);

    // 取り出してみる
    ret  := db.First(&user)
   
    return c.RenderJson(ret)
}
```

できた。`http://localhost:9000`にアクセス。

```
{
  "Value": {
    "id": 1,
    "name": "go tarou",
    "age": 34
  },
  "Error": {
    "Number": 1103,
    "Message": "Incorrect table name ''"
  },
  "RowsAffected": 0
}
```

おー、取り出せてる。なんか違う情報までついてるから、
Value部分だけ取り出すのはどうするんだろう。。

一応データベース側も確認しておく。

```
mysql> select * from users;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | go tarou |   34 |
+----+----------+------+
1 row in set (0.01 sec)
```

なんとか、ORMを使ってmysqlとやりとりをすることができました。
ちょっとまだわからない部分があるけど、そこはおいおい。

ちなみに、実は、mysqlの接続部分でエラーが出てはまりました。
以下にメモしておきます。

##mysql接続でハマった。

```
(dial tcp 192.168.1.3:3306: connection refused)
```

というエラー。
`/etc/mysql/my.cnf`で

```
#bind-address           = 127.0.0.1
```
をコメントアウト。ポートがきちんと空いているかは、`netstat -tlpn`で確認できます。


再度接続。また、エラー。

```
(Error 1130: Host '192.168.1.2' is not allowed to connect to this MySQL server)
```

権限ないよう...。
めんどー。

```mysql
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 40
Server version: 5.5.40-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, 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
mysql> SELECT host,user FROM mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| 127.0.0.1 | root             |
| ::1       | root             |
| localhost | debian-sys-maint |
| localhost | root             |
| ubuntu-14 | root             |
+-----------+------------------+
5 rows in set (0.00 sec)
mysql>
```

```mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO root@'192.168.%' IDENTIFIED BY 'vagrant' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql>
mysql>
mysql> SELECT host,user FROM mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| 127.0.0.1 | root             |
| 192.168.% | root             |
| ::1       | root             |
| localhost | debian-sys-maint |
| localhost | root             |
| ubuntu-14 | root             |
+-----------+------------------+
6 rows in set (0.00 sec)

```


以上。