Goでデータベースを操作するには、
データベースに適したドライバーを
インポートする必要があります。
今回はSQLite3ですので、
こちらからもってくることが出来ます。
go get github.com/mattn/go-sqlite3 |
あとは、SQLite3を
インストールして準備完了です。
それでは実際に使ってみましょう。
コード内で行っていることは、
データベースにユーザ情報を登録して
データベースに検索をかけています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
package main import ( "database/sql" "fmt" "log" _ "github.com/mattn/go-sqlite3" ) type userInfo struct { id string email string pass string fName string lName string } func main() { //登録するユーザ情報 ui := &userInfo{ id: "jonhson123", email: "xxx@example.com", pass: "123", fName: "名前", lName: "苗字", } //データベースに情報を登録する err := saveUserInfo2DB(ui) if err != nil { log.Println(err) } fmt.Println("[+]Succsessd to save userInfo") //データベースに存在しない情報はマッチしない。 //ui.email = "example@example.jp.co" //ui.pass = "98765" //ユーザ情報がデータベースに存在するか確認。 id, bool, err := checkValidity(ui.email, ui.pass) if bool == false || err != nil { log.Println(err) } else if id == "" { log.Printf("[-]Email and Passward don't match [%s : %s]\n", ui.email, ui.pass) } else { fmt.Printf("[+]UserId id %s\n", id) } } func saveUserInfo2DB(user *userInfo) error { fmt.Println("[+]Save data to SQLite ...") db, err := sql.Open("sqlite3", "database.db") defer db.Close() if err != nil { log.Println("[-]sql.Open") return err } stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS user (UserID text PRIMARY KEY, Email text, Pass text, FirstName text, LastName text)") defer stmt.Close() if err != nil { log.Println("[-]sql.Prepare (create table: user)") return err } stmt.Exec() stmt, err = db.Prepare("INSERT INTO user (UserID, Email, Pass, FirstName, LastName) VALUES ($1, $2, $3, $4, $5)") defer stmt.Close() if err != nil { log.Println("[-]sql.Prepare (INSERT INTO user)") return err } stmt.Exec(user.id, user.email, user.pass, user.fName, user.lName) return nil } func checkValidity(email string, pass string) (string, bool, error) { fmt.Println("[+]Checking if login info matches...", email, " : ", pass) //name denotes user name registed in DB //e denotes email in DB //p denoted password in DB var userID, e, p string db, err := sql.Open("sqlite3", "database.db") defer db.Close() if err != nil { log.Println("[-]sql.Open", err) return "", false, err } rows, err := db.Query("SELECT UserID, Email, Pass FROM user WHERE Email = $1 AND Pass = $2", email, pass) //andとかを小文字にすると正常に動かない。 defer rows.Close() if err != nil { log.Printf("[-]db.Query") return "", false, err } for rows.Next() { err := rows.Scan(&userID, &e, &p) //引数とカラムの型が適切でないとエラーになる if err != nil { log.Println("[-]rows.Scan") return "", false, err } fmt.Println("[+]Match!: ", e, " : ", p) } err = rows.Err() if err != nil { log.Println(err) return "", false, err } return userID, true, nil } |
saveUserInfo2DB関数
データベースへの登録を行う。
checkValidity関数
メールアドレスとパスワードに該当する
ユーザidをデータベースから取得する
id、email、パスワード、名前の情報を持つ
UserInfo構造体を定義しています。
本来はクライアントからの
入力を保存しますが今回は、
main文内で指定しています。
SQLiteやPostgresなどのRDBSは、
sql.Open()して、SQL文を実行
という簡単な流れです。
Closeするのをお忘れなく。
SELECT文を使うときは、
Queryメソッドを使います。
ちなみにQueryメソッドは、
検索にヒットしなかったら、
エラーが返って来そうですが、
ヒットしなくてもnilが返ってきます。
sql文に不備があるとエラーを返します。
条件に合うレコードが複数あると、
複数のタプルが返ってきます。
Nextメソッドで個々を
対象とすることが出来ます。
また、取得したタプルは、
Scanメソッドを使うことで、
引数に指定した変数に代入出来ます。
注意ですが、Scan()の引数に渡す際は、
"ポインタ"を渡さないと上手く動作しません。
また、カラムの型と
引数のポインタが指す変数の型が、
それぞれ一致しないとエラーが返ります。
万が一、期待せぬことに、
ユーザ情報のレコードが2つヒットすると、
2行目の情報が最終的な値になります。
rows.Scan()で1レコード目が
2レコード目によって上書きされるからです。
上の例とは違って、
複数のレコード情報が欲しい場合は、
多重スライスを作って、
rows.Next()でループが回るたびに、
append()などしていく必要があります。

今回は紹介のためにあえて、
Queryメソッドを使いましたが、
条件に1列しかマッチしないのが
自明である場合などは、
QueryRowメソッドを使用します。
そこでQueryRowを用いた
別の例を見てみましょう。
ユーザIDを引数として、
それがデータベースに登録されているか
真偽を確かめる場合です。
ユーザIDの有無を確かめる
あるかないかを確認するだけなので
True or Falseが欲しいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func checkUID(id string) bool { fmt.Println("[+]Checking if UID matches...", id) exist := false db, err := sql.Open("sqlite3", "database.db") defer db.Close() if err != nil { log.Println("[-]sql.Open: ", err) return exist } row := db.QueryRow("SELECT EXISTS (SELECT * FROM user WHERE UserID = $1)", id) if err := row.Scan(&exist); err != nil { //idがなかったらエラーが返る log.Println("[-]No uid in DB: ", err) return exist } return exist } |
QueryRowに、SELECT EXIST ... で
データベースに検索をかけます。
そしてScanメソッドを使うことで、
真偽の結果が分かります。
なければエラーとしてかえってきます。
ユーザIDがあればexisitには、
Trueが入っています。
以上です。
最後まで読んでいただきありがとうございました。
参考 : https://pkg.go.dev/database/sql?tab=doc#example-DB.Prepare
参考 : https://golang.shop/post/go-databasesql-04-retrieving-ja/