💠

[入門]GoでSQLite3を使いデータベース操作を行ってみる[Mac]

2023/10/11に公開

インストール

今回はgo-sqlite3を利用する

sqlite

  1. brew install sqlite

  2. sqlite3
    下記のような表示となればok

SQLite version 3.39.5 2022-10-14 20:58:05
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> 
  1. .exitで抜ける

go-sqlite3

go get github.com/mattn/go-sqlite3

ただし、下記の通り、GoでビルドするにあたりC言語のライブラリをインポートするため、CGO_ENABLE=1gccのコンパイラが必要
既に入っている方は次のセクションをスキップしてください。

go-sqlite3 is cgo package. If you want to build your app using go-sqlite3, you need gcc. However, after you have built and installed go-sqlite3 with go install github.com/mattn/go-sqlite3 (which requires gcc), you can build your app without relying on gcc in future.
Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compiler present within your path.

Xcode

  1. Xcode-リソースからインストールする
  2. xcode-select --install
    CLIのインストール
    私は既にインストールされていたためxcode-select: note: Command line tools are already installed. Use "Software Update" in System Settings or the softwareupdate command line interface to install updatesと表示されました
  3. gcc --version
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

データベース操作

nameとageのカラムを持つデータベースを作成する

  1. 次のコードを記述
package main

import (
	"database/sql"
	"log"

	_ "github.com/mattn/go-sqlite3" //ビルド時にコンパイルすることでSQLにアクセス出来る
)

var DbConnection *sql.DB

func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}
}
  1. go run main.goを実行
    example.sqlというファイルができていればok
  2. sqlite3 example.sqlをターミナルで実行
  3. sqlite> .table
    personというテーブルが出来ていることを確認する

personテーブルに値をinsertする

  1. personに対して、データを入れていく
    一旦はcmd,errを上書きする形で実行する。
    後にシングルセレクト、マルチセレクトを行いたいため別レコードを2つか3つほど入れると良いです
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "INSERT INTO person (name, age) VALUES (?, ?)" //SQLインジェクション対策
	_,err = DbConnection.Exec(cmd, "Finn", 30)
	if err != nil{
		log.Fatalln(err)
	}
}

https://developer.mozilla.org/ja/docs/Glossary/SQL_Injection

  1. select * from personで内容を確認
sqlite> select * from person;
Finn|30
Emma|15
Watson|40

レコードのupdate

先ほどとほぼ同様に行う

  1. updateコマンドを記述
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "UPDATE person SET age = ? WHERE name = ?"
	_, err = DbConnection.Exec(cmd, 1000, "Finn")
	if err != nil{
		log.Fatalln(err)
	}
}
  1. selectで確認
    1000と変更されていたのでok

マルチセレクト

  1. cmdをアップデート
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "SELECT * FROM person"
	rows,_ := DbConnection.Query(cmd)
	defer rows.Close()

}
  1. Person structを作成する
type Person struct {
	Name string
	Age int
}
  1. Personスライスにデータを入れる
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	cmd = "SELECT * FROM person"
	rows,_ := DbConnection.Query(cmd)
	defer rows.Close()

	//追加
	var pp []Person
	for rows.Next(){
		var p Person
		err := rows.Scan(&p.Name, &p.Age) //アドレスを引数に渡すろstructにデータを入れてくれる
		if err != nil{
			log.Fatalln(err)
		}
		pp = append(pp,p)
	}
	for _,p := range pp {
		fmt.Println(p.Name,p.Age)
	}
}
  1. 以下のようなデータが表示されればok
Finn 1000
Emma 15
Watson 40

シングルセレクト

  1. cmdをアップデート
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	_, err := DbConnection.Exec(cmd) 
	if err != nil{
		log.Fatalln(err)
	}
	//追加
	cmd = "SELECT * FROM person where age = ?"
	row := DbConnection.QueryRow(cmd, 15) //存在しているレコードのageを入力
	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)
}
  1. 実行し、確認
    レコードが表示されればok
Emma 15
  1. 存在しないレコードをqueryした場合
row := DbConnection.QueryRow(cmd, 15)
↓
row := DbConnection.QueryRow(cmd, 9999999)
  1. エラーが表示されることを確認する
    No row

レコードの削除

  1. コードを更新
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	_, err := DbConnection.Exec(cmd) 
	if err != nil{
		log.Fatalln(err)
	}
	//追加
	cmd = "DELETE FROM person WHERE name = ?"
	DbConnection.Exec(cmd, "Finn")
	if err != nil{
		log.Fatalln(err)
	}
}
  1. 対象が消えていればok

Discussion