
GoのプログラムでSQLite使いたいんだけど…
アプリ開発をしていく上で、データベースの存在は外すことができません。
今回はGoでデータベースを扱うための基本をSQLite3を例にしてお伝えしていきます。
当ブログではSQLite3をGoで使用する環境構築をご紹介していますので、環境構築されていない方はご参考にしてください。
データベースの基本・CRUDとは
SQLiteやMySQLなどのリレーショナルデータベースの基本として覚えておいてほしいことにCRUDがあります。
C(Create) | CREATE文(データベース作成) INSERT文(レコード作成) | データの作成 |
R(Read) | SELECT文 | データの読み込み |
U(Update) | UPDATE文 | データの更新 |
D(Delete) | DELETE文 | データの削除 |
CRUDはデータベースの操作や管理を行うことであることを前提知識として押さえておきましょう。
GoでのSQLiteを扱う前準備
GoでSQLiteを扱うには前準備が必要です。
- STEP1GoでSQLite3を使用できる環境構築
- STEP2
- STEP3データベースファイル関連を扱うフォルダ作成
データベースを扱う専用の
models
フォルダを作成 - STEP4データベースを扱う初期設定
models
フォルダにファイルを作成して初期設定する
以上になります。
今回使用するファイルは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)
}
}

データベースの初期設定はパターン化しています。
データベースを作成する 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 exists
の if 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