私が普段使っているDBは、PostgreSQLを使っているのですが、構築手順が面倒くさいし、なによりDBサーバ立てるのを省略したかったです。
ですので、SQLiteを使ってDB構築の手を抜くことにしました。
今日のところは、mattn/go-sqlite3 に _example/simple/simple.go
というサンプルファイルがあったので、これを動くことを確認するところまでやりました。
/*
C:\Users\ebata\kese\gonet-html\1-1
go get github.com/mattn/go-sqlite3
どういう訳か、VSCodeのデバッグでトレースができなかったので、fmt.Println("----->10") と入れて確認をしている。
このプログラムは、
*/
package main
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/mattn/go-sqlite3"
)
func main() {
os.Remove("./foo.db")
fmt.Println("----->10")
db, err := sql.Open("sqlite3", "./foo.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sqlStmt := `
create table foo (id integer not null primary key, name text);
delete from foo;
`
_, err = db.Exec(sqlStmt)
if err != nil {
log.Printf("%q: %s\n", err, sqlStmt)
return
}
fmt.Println("----->9")
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}
fmt.Println("----->8")
stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
for i := 0; i < 100; i++ {
_, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
if err != nil {
log.Fatal(err)
}
}
tx.Commit()
fmt.Println("----->7")
rows, err := db.Query("select id, name from foo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
fmt.Println("----->6")
err = rows.Err()
if err != nil {
log.Fatal(err)
}
fmt.Println("----->5")
stmt, err = db.Prepare("select name from foo where id = ?")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
var name string
err = stmt.QueryRow("3").Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
fmt.Println("----->4")
_, err = db.Exec("delete from foo")
if err != nil {
log.Fatal(err)
}
fmt.Println("----->3")
_, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')")
if err != nil {
log.Fatal(err)
}
fmt.Println("----->2")
rows, err = db.Query("select id, name from foo")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err = rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
fmt.Println("----->1")
err = rows.Err()
if err != nil {
log.Fatal(err)
}
fmt.Println("----->0")
}
もう一つのサンプルコード
https://qiita.com/geniusmaaakun/items/b3cb44de3b10a526be98 を参照させて頂き、微小修正
package main
/*
C:\Users\ebata\kese\gonet-html\1-1-1
sqliteをインストールする際の手順の確認
# ドライバのインストール
go get github.com/mattn/go-sqlite3
*/
import (
"database/sql"
"fmt"
"log"
"os"
//インポート _にしないとコンパイルエラーになる。使用しない為
_ "github.com/mattn/go-sqlite3"
)
var DbConnection *sql.DB
type Person struct {
Name string
Age int
}
func main() {
os.Remove("./example.sql") // これを入れないと、DBが太り続ける
//1
//DBを開く なければ作成される
DbConnection, _ := sql.Open("sqlite3", "./example.sql")
//終わったら閉じる
defer DbConnection.Close()
//DB作成 SQLコマンド
cmd := `CREATE TABLE IF NOT EXISTS person(
name STRING,
age INT)`
//実行 結果は返ってこない為、_にする
_, err := DbConnection.Exec(cmd)
//エラーハンドリング
if err != nil {
fmt.Println("エラー")
log.Fatalln(err)
}
//ターミナル
//sqlite3
//.table
//SELECT * FROM tablename;
//で確認
//2 CRUD処理
//Create
//データを追加
//VALUES (?, ?) 値は後で渡す。セキュリテイの関係でこのようにする方がいい
//SQLインジェクション 悪意あるコマンドでDBが操作されてしまうのを防ぐ ?でエスケープしてくれる
cmd = "INSERT INTO person (name, age) VALUES (?, ?)"
//実行
//レコードを取得する必要のない、クエリはExecメソッドを使う
//第二引数からは、コマンド?部の値
_, err = DbConnection.Exec(cmd, "Nancy", 20)
if err != nil {
log.Fatalln(err)
}
_, err = DbConnection.Exec(cmd, "Mike", 20)
if err != nil {
log.Fatalln(err)
}
_, err = DbConnection.Exec(cmd, "Tom", 55)
if err != nil {
log.Fatalln(err)
}
//Update
//データの更新 Mike が存在する場合
cmd = "UPDATE person SET age = ? WHERE name = ?"
_, err = DbConnection.Exec(cmd, 25, "Mike")
if err != nil {
log.Fatalln(err)
}
//Read
//Get All
//マルチセレクト
//データ全てをループで表示
//Queryは全て取得する
cmd = "SELECT * FROM person"
rows, _ := DbConnection.Query(cmd)
defer rows.Close()
//structを作成
var pp []Person
//取得したデータをループでスライスに追加 for rows.Next()
for rows.Next() {
var p Person
//scan データ追加
err := rows.Scan(&p.Name, &p.Age)
if err != nil {
log.Println(err)
}
pp = append(pp, p)
}
err = rows.Err()
if err != nil {
log.Fatalln(err)
}
//表示
for _, p := range pp {
fmt.Println(p.Name, p.Age)
}
//特定のデータを取得
cmd = "SELECT * FROM person where age = ?"
//age = 20にして実行
//QueryRowは最初の一件だけ取得する。
//row := DbConnection.QueryRow(cmd, 20)
//row := DbConnection.QueryRow(cmd, 25)
row := DbConnection.QueryRow(cmd, 55)
var p Person
err = row.Scan(&p.Name, &p.Age)
if err != nil {
//データがなかったら
if err == sql.ErrNoRows {
log.Println("No row")
//それ以外のエラー
} else {
log.Println(err)
}
}
fmt.Println(p.Name, p.Age)
//Delete
//データの削除 全て
cmd = "DELETE FROM person WHERE name = ?"
_, err = DbConnection.Exec(cmd, "Nancy")
if err != nil {
log.Fatalln(err)
}
//マルチセレクト テーブルもSQLインジェクション対策
//こちらを推奨
//データを構造体に入れて表示
//テーブルはSQLインジェクション対策が使えない
tableName := "person"
//テーブル名指定は?が使えない為、%sを使う。
//後に対応されるかも?
cmd = fmt.Sprintf("SELECT * FROM %s", tableName)
rows1, _ := DbConnection.Query(cmd)
defer rows1.Close()
var pp1 []Person
//パターンとして覚える
for rows1.Next() {
var p Person
//データを構造体に追加
err := rows1.Scan(&p.Name, &p.Age)
if err != nil {
log.Println(err)
}
//ppに追加
pp1 = append(pp1, p)
}
//まとめてエラーチェック
err = rows1.Err()
if err != nil {
//エラーなら終了
log.Fatalln(err)
}
for _, p := range pp1 {
fmt.Println(p.Name, p.Age)
}
}