SQLiteのCRUD操作をGoで使用するときの構文パターン

Go言語
この記事は約16分で読めます。
Go初学者
Go初学者

GoのプログラムでSQLite使いたいんだけど…

この記事ではGoでSQLiteのCRUD操作の基本を理解できます!
  • GoでSQLite3でのCRUD操作のパターンについて
  • SQLite3の初期設定を init() で設定する

アプリ開発をしていく上で、データベースの存在は外すことができません。

今回はGoでデータベースを扱うための基本をSQLite3を例にしてお伝えしていきます。

当ブログではSQLite3をGoで使用する環境構築をご紹介していますので、環境構築されていない方はご参考にしてください。

この記事ではSQL文の詳細には触れていません。ごめんなさい。

もりぴ
この記事を書いた人

XHTML1.0時代にHTML&CSSを勉強した経験あり。無趣味だった私が2020年5月からプログラミング学習を開始し現在も挫折せずに趣味で学習を楽しんでいる51歳。プログラミングの楽しさをブログを通してお伝えしていきます。

もりぴをフォローする

データベースの基本・CRUDとは

SQLiteやMySQLなどのリレーショナルデータベースの基本として覚えておいてほしいことにCRUDがあります。

C(Create)CREATE文(データベース作成)
INSERT文(レコード作成)
データの作成
R(Read)SELECT文データの読み込み
U(Update)UPDATE文データの更新
D(Delete)DELETE文データの削除

CRUDはデータベースの操作や管理を行うことであることを前提知識として押さえておきましょう。

GoでのSQLiteを扱う前準備

GoでSQLiteを扱うには前準備が必要です。

GoでのSQLiteを扱う前準備

以上になります。

今回使用するファイルはGitHubで公開していますので、GitHubからダウンロードしてください。

データベース関連のフォルダの作成

ini_test フォルダの直下に models フォルダを作成し、データベースの初期設定とデータベース作成用の base.go ファイルを作成します。

今回のフォルダ構成は下記の通りです。

morip@morip-PC1:~/go/src/ini_test$ tree
.
├── app // 新規作成
│   └── models  // データベース関連のフォルダ
│       └── base.go  // データベースの初期設定とデータベース作成
├── config
│   └── config.go
├── config.ini
├── go.mod
├── go.sum
├── main.go
├── utils
│   └── logging.go
├── webapp2.log
└── webapp2.sql

4 directories, 9 files

データベースの初期設定

データベース関連の初期設定をします。

config.ini の情報を必要とするのでconfig関連の設定は終了していることが前提です。

今回はユーザー情報のデータベース作成 users を前提といたしましょう。

もりぴ
もりぴ

ちなみにデータベース名は複数形が望ましいです。

// base.go

package models  // package名はフォルダ名と一緒

import (
    "database/sql"
    "ini_test/config"
    "log"

    // 重要!コードで使用していないパッケージは「_」を前に記述
    // VSCodeでエラーになる場合は go mod tidy を実行
    _ "github.com/mattn/go-sqlite3"
)

// データベースへアクセスするための変数
var Db *sql.DB

// エラー用の変数
var err error

// 定数でテーブル名を宣言
const (
    // テーブル名は複数形が望ましい
    // 定数名は任意で!
    tableNameUser = "users"
)

// init()でmain関数より前に実行
func init() {
    // config.goで設定した内容でアクセス
    Db, err = sql.Open(config.Config.SQLDriver, config.Config.DBName)
    if err != nil {
	log.Fatalln(err)
    }
}
もりぴ
もりぴ

データベースの初期設定はパターン化しています。

_ "github.com/mattn/go-sqlite3" _ は、コード内で使用しているコマンドは無いけれどドライバとして必要な場合に記述します。

データベースを作成する CREATE文

データベースを作成するための CREATE をコードを記述していきます。

// base.go

package models

import (
    "database/sql"
    "ini_test/config"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

var Db *sql.DB

var err error

const (
    tableNameUser = "users"
)

func init() {
    Db, err = sql.Open(config.Config.SQLDriver, config.Config.DBName)
    if err != nil {
	log.Fatalln(err)
    }

    // 定数で宣言したテーブルが無ければ作成する if not exists
    cmdU := fmt.Sprintf(`create table if not exists %s(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name STRING,
        email STRING,
        created_at DATETIME)`, tableNameUser)

    // cmdUを実行
    _, err = Db.Exec(cmdU)
    if err != nil {
	log.Fatalln(err)
    }
}

fmt.Sprintf() を使用して文字列として、変数 cmdU に代入します。

create table if not existsif not exists はテーブルが無かったら作成するという意味でテーブルがあれば作成されません。

カラムに関しては、あなたのアプリで必要になるカラムを設定しましょう。

もりぴ
もりぴ

コードの記述に間違いがないのにVSCodeでエラーになったら go mod tidy を忘れずに!

データベースを作成するには main.go から実行します。

// main.go

package main

import (
    "fmt"
    "ini_test/app/models"
)

func main() {
    // 下記のコードでテーブルが作成されていないければ作成
    fmt.Println(models.Db)
}
// 出力結果
$ go run main.go
&{0 {webapp2.sql 0xc00013a0e0} 0 {0 0} [0xc000154000] map[] 0 1 0xc0001020c0 false map[0xc000154000:map[0xc000154000:true]] map[] 0 0 0 0 <nil> 0 0 0 0 0x4cc900}
$ sqlite3 webapp2.sql
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .table
users
sqlite> .exit
もりぴ
もりぴ

SQLite3を立ち上げて users テーブルが作成されています。

CRUD操作を実施する

ここからは、新たにユーザーを管理するためのファイル user.go を作成していきます。

user.go にテーブル作成以外のコードを記述して管理します。

morip@morip-PC1:~/go/src/ini_test$ tree.
├── app
│   └── models
│       ├── base.go
│       └── user.go  // 新規作成
├── config
│   └── config.go
├── config.ini
├── go.mod
├── go.sum
├── main.go
├── utils
│   └── logging.go
├── webapp2.log
└── webapp2.sql

4 directories, 10 files

レコードを新規作成する・INSERT文

それでは、user.go ファイルにレコードを新規作成するための INSERT のコードを記述いていきます。

// user.go

package models

import (
    "log"
    "time"
)

// ユーザー情報を構造体に
type User struct {
    ID        int
    Name      string
    Email     string
    CreatedAt time.Time
}

// ユーザー情報をデータベースに追加(INSERT)
func (u *User) CreateUser() (err error) {
    cmd := `insert into users(
        name,
        email,
        created_at) values (?, ?, ?)`

    _, err = Db.Exec(cmd,
	u.Name,
	u.Email,
	time.Now())

    if err != nil {
	log.Fatalln(err)
    }
    return err
}

? はSQlインジェクションの攻撃からの防止です。

レコードの追加は main.go から実行します。

// main.go

package main

import (
    "fmt"
    "ini_test/app/models"
)

func main() {
    // ユーザーを作成する
    user := &models.User{}
    user.Name = "user1"
    user.Email = "user1@test.com"
    // 画面に出力
    fmt.Println(user)
    // レコードを追加
    user.CreateUser()
}
// 出力結果
$ go run main.go
&{0 user1 user1@test.com 0001-01-01 00:00:00 +0000 UTC}
もりぴ
もりぴ

では、webapp2.sql を確認してみましょう!

$ sqlite3 webapp2.sql
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> select * from users;
1|user1|user1@test.com|2021-09-05 16:27:29.443972337+09:00
もりぴ
もりぴ

データがきちんと入っていますね!

データを読み込む・SELECT文

登録したデータを読み込む SELECT のコードを記述していきます。

今回はユーザーのデータを1件読み込む QueryRow() を使用しています。

// user.go

package models

import (
    "log"
    "time"
)

// ユーザー情報を構造体に
type User struct {
    ID        int
    Name      string
    Email     string
    CreatedAt time.Time
}

// ユーザー情報の取得
func GetUser(id int) (user User, err error) {
	user = User{}
	cmd := `select id,
    name,
    email,
    created_at
    from users
    where id = ?`
    err = Db.QueryRow(cmd, id).Scan(
	&user.ID,
	&user.Name,
	&user.Email,
	&user.CreatedAt,
    )
    return user, err
}

それでは、main.go で実行してみましょう。

// main.go

package main

import (
    "fmt"
    "ini_test/app/models"
)

func main() {
    // ユーザー情報を取得
    // ユーザーIDは1
    user, _ := models.GetUser(1)
    fmt.Println(user)
}
// 出力結果
$ go run main.go
{1 user1 user1@test.com 2021-09-05 16:27:29.443972337 +0900 +0900}

ユーザーIDが 1 の情報を取得できました。

データを更新する・UPDATE文

ユーザー情報に変更がある場合はデータを更新する必要があります。

その時に使用されるのが UPDATE です。

ユーザーIDから名前とメールアドレスの情報を更新してみます。

それでは、実際にコードで確認していきましょう。

// user.go

package models

import (
    "log"
    "time"
)

// ユーザー情報を構造体に
type User struct {
    ID        int
    Name      string
    Email     string
    CreatedAt time.Time
}

// ユーザー情報の更新
func (u *User) UpdateUser() (err error) {
	cmd := `update users set name = ?,
    email = ?
    where id = ?`
    _, err = Db.Exec(cmd, u.Name, u.Email, u.ID)
    if err != nil {
	log.Fatalln(err)
    }
    return err
}

それでは、main.go で実行してみましょう。

// main.go

package main

import (
    "fmt"
    "ini_test/app/models"
)

func main() {
    // ユーザー情報の更新
    user, _ := models.GetUser(1)
    user.Name = "morip"
    user.Email = "morip@test.com"
    user.UpdateUser()
    user, _ = models.GetUser(1)
    fmt.Println(user)
}
// 出力結果
$ go run main.go
{1 morip morip@test.com 2021-09-05 16:27:29.443972337 +0900 +0900}

SQLite3でデータベースが更新されているか確認します。

$ sqlite3 webapp2.sql
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> select * from users;
1|morip|morip@test.com|2021-09-05 16:27:29.443972337+09:00
sqlite> 
もりぴ
もりぴ

データベースも更新されました!

データベースの削除・DELETE文

DELETE でデータの削除を行っていきます。

削除を実施するために、事前にユーザーを1名追加しておきます。(コードは省略)

$ sqlite3 webapp2.sql
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> select * from users;
1|morip|morip@test.com|2021-09-05 16:27:29.443972337+09:00
2|user2|user2@test.com|2021-09-06 07:28:10.419216256+09:00  // 追加
// user.go

package models

import (
    "log"
    "time"
)

// ユーザー情報を構造体に
type User struct {
    ID        int
    Name      string
    Email     string
    CreatedAt time.Time
}

// ユーザーを削除
func (u *User) DeleteUser() (err error) {
    cmd := `delete from users where id = ?`
    _, err = Db.Exec(cmd, u.ID)
    if err != nil {
        log.Fatalln(err)
    }
    return err
}

それでは、追加した user2 のデータを削除しましょう。

// main.go

package main

import (
    "fmt"
    "ini_test/app/models"
)

func main() {
    // ユーザー情報を取得
    // ユーザーIDは2
    user, _ := models.GetUser(2)
    fmt.Println(user)

    // ユーザーの削除
    user.DeleteUser()

    // ユーザーが削除されているか確認
    user, _ = models.GetUser(2)
    fmt.Println(user)
}
// 出力結果
$ go run main.go
{2 user2 user2@test.com 2021-09-06 07:28:10.419216256 +0900 +0900}
{0   0001-01-01 00:00:00 +0000 UTC}  // ユーザーが削除されデータが無い

SQLite3でも確認します。

$ sqlite3 webapp2.sql
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> select * from users;
1|morip|morip@test.com|2021-09-05 16:27:29.443972337+09:00

データが1件で user2 のデータが削除されているのが確認できました。

【最後に】GoでSQLite3の学習をして私が感じたこと

今回はSQLite3でのGoプログラムでデータベース操作の流れを確認してきました。

コードを見ただけではわからないところも多いので、実際にエディタで動きを確認することをおすすめいたします。

私がGo言語を学習していて、簡単なアプリケーションを作成した時に思ったことは…

もりぴ
もりぴ

データベースの操作はある程度パターン化されているな。

私を含め、プログラミング学習の初心者は覚えることが多すぎますし、まずは動くアプリを自分で作成することが喜びになるでしょう。

GoでSQLite3を使用する構文パターンは、私の備忘録として時にはコピペして使用しやすいように記事にしました。

特にプログラミングの学習は基本を終えて、データベースを扱う辺りから楽しさと苦しさを感じます。

ここを共に乗り越えていきましょう!

comment

タイトルとURLをコピーしました