Go 自体は、database/sql
インターフェイス層に相当するデータベース アクセス層を抽象化するためにこのパッケージを提供します。ただし、特定のデータベースにアクセスするには、そのデータベースに対応するドライバーをインストールする必要があります。MySQL の場合は、次のコマンドを実行してドライバーをインストールします。
go get -u github.com/go-sql-driver/mysql
ドライバーを使用すると、後でデータベースにアクセスするのが非常に簡単になります。
mysqlに接続する
接続パラメータを設定することによりsql.open
、この関数は実際にデータベースにアクセスしません。
db, err := sql.Open("mysql", "username:password@(127.0.0.1:3306)/dbname?parseTime=true")
db.ping
を通じてデータベースにアクセスし、接続が正常かどうかを確認します。接続パラメータが間違っている場合は、変数 err が割り当てられます。
err := db.Ping()
MySQL にアクセスして CURD 操作を実行する
1 テーブルの作成
ユーザー テーブルを作成し、そのテーブル作成ステートメントが次のようになっているとします。
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);
go でテーブルを作成する操作は次のようになります。 err を使用してテーブルの作成に問題があるかどうかを判断できます。
query := `
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);`
// Executes the SQL query in our database. Check err to ensure there was no error.
_, err := db.Exec(query)
2 挿入データ
日付データを挿入する必要がある場合は、time
このパッケージを導入する必要があります
import "time"
username := "johndoe"
password := "secret"
createdAt := time.Now()
// Inserts our data into the users table and returns with the result and a possible error.
// The result contains information about the last inserted id (which was auto-generated for us) and the count of rows this query affected.
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
この変数はresult
、挿入時のデータベースの変更情報 (挿入されたデータ行の ID や影響を受ける行の数など) を返すことができます。
userID, err := result.LastInsertId()
3 クエリデータ
3.1 単一データのクエリ
この簡潔な記述方法ではdb.QueryRow
、単一データのクエリを有効にし、一連の変数をカプセル化することで、各変数を宣言するvar()
必要がなくなります。var
var (
id int
username string
password string
createdAt time.Time
)
// Query the database and scan the values into out variables. Don't forget to check for errors.
query := `SELECT id, username, password, created_at FROM users WHERE id = ?`
err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt)
3.2 複数のデータのクエリ
複数のデータのクエリは単一のデータとよく似ていますが、db.Query
ここでは関数が呼び出され、複数のレコードを返すことができる点が異なりますが、db.QueryRow
最大でも 1 つのレコードしか返されません。
複数のデータのクエリ結果については、Go フィールドとデータベース フィールド間の 1 対 1 マッピングを実現する構造を定義し、各行レコードを繰り返しスキャンして構造メンバーにカプセル化する必要があります。
type user struct {
id int
username string
password string
createdAt time.Time
}
rows, err := db.Query(`SELECT id, username, password, created_at FROM users`) // check err
defer rows.Close()
var users []user
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt) // check err
users = append(users, u)
}
err := rows.Err()
データベースにデータがある場合、ユーザーの構造体配列は次のようになります。
users {
user {
id: 1,
username: "johndoe",
password: "secret",
createdAt: time.Time{
wall: 0x0, ext: 63701044325, loc: (*time.Location)(nil)},
},
user {
id: 2,
username: "alice",
password: "bob",
createdAt: time.Time{
wall: 0x0, ext: 63701044622, loc: (*time.Location)(nil)},
},
}
4 データを削除する
実行するとdb.Exec
削除操作を実現できます
_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1) // check err
完全なコード
package main
import (
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "root:mysql520@(127.0.0.1:3306)/demo?parseTime=true")
if err != nil {
log.Fatal(err)
}
if err := db.Ping(); err != nil {
log.Fatal(err)
}
{
// Create a new table
query := `
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);`
if _, err := db.Exec(query); err != nil {
log.Fatal(err)
}
}
{
// Insert a new user
username := "johndoe"
password := "secret"
createdAt := time.Now()
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
if err != nil {
log.Fatal(err)
}
id, err := result.LastInsertId()
fmt.Println(id)
}
{
// Query a single user
var (
id int
username string
password string
createdAt time.Time
)
query := "SELECT id, username, password, created_at FROM users WHERE id = ?"
if err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt); err != nil {
log.Fatal(err)
}
fmt.Println(id, username, password, createdAt)
}
{
// Query all users
type user struct {
id int
username string
password string
createdAt time.Time
}
rows, err := db.Query(`SELECT id, username, password, created_at FROM users`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var users []user
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt)
if err != nil {
log.Fatal(err)
}
users = append(users, u)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v", users)
}
{
_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1)
if err != nil {
log.Fatal(err)
}
}
}