はじめに
私のこれまで基本的にJavaしかやって来ませんでした。
また利用するDBもPostgreSQLがメインだったのでOracleDBとは幸いなことにあまり関わってこなかったのですが、仕事関係で色々ありGo言語+OracleDBを使うことになりました。
。
いざ始めてみるとライブラリの設定やアプリのDockerイメージビルドでかなり苦労しながらもGitHubやStackoverflowと睨めっこが続きました。
というわけでこの苦労を忘れてしまわないように、メモとして残そうと思い立ち今に至ります。
環境
私の実行環境は以下の通りです。
環境/ツール類 | バージョン |
---|---|
OS | Windows10 |
Ubuntu(WSL) | 20.04.4 |
Golang | 18.5 |
Oracle | 19c(19.3.0) |
Docker | 20.10.17 |
Docker-Compose | v2.6.1 |
1. Oracle19cの準備
まずはじめにOracle19cを用意しないと何も始まりません。
普通にOracleをインストールすればいいのですが、自分の環境をOracleで汚したくなかったのでコンテナで起動することにしました。
調べると結構簡単に自分でビルドしてコンテナ化できるみたいなのでその方法でOracleDBの起動を行います。
下記参考リンクの手順通りに(バージョンを変えて)進めるだけでOKですが、一応私の実施手順も以降に記載します。
1.1 Oracle公式リポジトリのクローン
Githubの公式リポジトリからOracleDBのビルド用資材をクローンします。
$ git clone https://github.com/oracle/docker-images.git
$ cd docker-images
1.2 Oracle Database 19cのダウンロードとイメージのビルド
Oracle Database Software DownloadsからOracle19c本体資材をダウンロードします。
Oracle19cの場合、DockerfileのベースイメージがoraclelinuxなのでLinux x86-64のzipを選択します。。。
が!!!!ここで面倒なことが発生します。
それはOracleアカウントが必要になるということです。
Oracleアカウントを持っていない人は「プロファイルの作成」を行う必要があるのですが、さらに面倒なのが会社名や会社住所が必須入力項目となっている点です。
個人の検証用で利用したいのに会社名必須とはどうすれば?ということでググってみると下記の記事がヒットしました。
どうやら個人の場合は↓の通り設定すればOKとのことです。
- 部署・役職名:「個人」
- 勤務先電話番号:個人携帯の電話番号
- 会社名:個人のフルネーム
これらの面倒なアカウント作成が完了するとようやく、目当てのzipファイルダウンロードが可能となります。
zipファイルのダウンロードできたらファイルを解凍せずにdocker-images/OracleDatabase/SingleInstance/dockerfiles/19.3.0/直下に格納します。
その後、下記shellスクリプトを実行し、Dockerイメージのビルドを行います。
docker-images$ ./OracleDatabase/SingleInstance/buildDockerImage.sh -v 19.3.0 -e -i
ビルドには結構時間がかかるのでビルド完了まで時間をつぶします。
-vオプションについて
-v
で指定するバージョンは11.2.0.2, 12.1.0.2, 12.2.0.1, 18.3.0, 18.4.0, 19.3.0, 21.3.0
から選択可能です。
今回は利用するバージョンは19cなので19.3.0
を指定します。
詳細はGithubのREADMEを参照してください。
1.3 Oracle19cコンテナの起動とPDBへの接続確認
Dockerイメージのビルドが完了したらコンテナを起動します。
コンテナの起動にはdocker run
コマンドを利用してもよいのですが、何度も同じ環境を起動できるように下記内容のdocker-compose
ファイルを作成します。
$ mkdir oracledb
$ chmod 777 ./oracledb
version: "3.9"
services:
db:
image: oracle/database:19.3.0-ee
container_name: oracle19c
volumes:
- ./oracledb:/opt/oracle/oradata
ports:
- 1521:1521
- 5500:5500
environment:
- ORACLE_PWD=oracle
- ORACLE_SID=GODB
- ORACLE_PDB=GOPDB
その後、バックグラウンドオプションの-d
を付けてdocker-compose
コマンドでコンテナを起動します。
起動には環境によりますが数十分近くかかるので気長に待ちます。
$ docker-compose -f oracle19c-docker-compose.yaml up -d
バックグラウンド実行について
バックグラウンド実行しないとずーっとOracleの稼働ログが出力され続けるので-dでバックグラウンド実行させることを推奨します。
ログは下記コマンドで確認し、「DATABASE IS READY TO USE!」と出力されればOKです。
$ docker logs -f oracle19c
・・・細かなログは省略
#########################
DATABASE IS READY TO USE!
#########################
1.4 接続用ユーザの作成
単純にコンテナ起動させた状態だと管理者系のユーザ(SYS, SYSTEM, PDBADMIN)しかいません。
なのでアプリでDB操作を行うユーザの作成が必要となります。
まずは起動したコンテナにログインしてsqlplus
でOracleDBに入ります。
$ docker exec -it oracle19c bash
$ sqlplus SYSTEM/oracle@GODB
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Sep 12 14:20:40 2022
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL>
後は下記リンク先の手順に沿ってPDBユーザを作成します。
まずはSYSTEMユーザにログインしてPDBADMINにユーザ作成権限を付与する。
SQL> alter session set container = GOPDB;
Session altered.
SQL> show con_name;
CON_NAME
------------------------------
GOPDB
SQL> grant grant any privilege to PDBADMIN;
Grant succeeded.
SQL> grant grant any role to PDBADMIN;
Grant succeeded.
SQL> exit;
権限が付与できたのでPDBADMINにログインしてユーザを作成します。
$ sqlplus pdbadmin/oracle@GOPDB
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Sep 12 14:26:09 2022
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL>
SQL> grant create user to PDB_DBA;
Grant succeeded.
SQL> create user gouser identified by pwd default tablespace users temporary tablespace temp;
User created.
SQL> grant unlimited tablespace to gouser;
Grant succeeded.
SQL> grant connect, resource to gouser;
Grant succeeded.
最後に作成したユーザでPDBに接続できればOK。
私の環境にはA5M2というツールが入っているのでそれを使います。
設定項目 | 設定値 |
---|---|
ホスト名 | loalhost |
ポート番号 | 1521 |
サービス名(PDB名) | GOPDB |
ユーザID | gouser |
パスワード | pwd |
接続確認ができればとりあえずOracleDBの準備はOKです。
2. 開発環境の構築
次にGoの開発環境を構築します。
Windows環境を利用しているのですが、Windows環境だとpkg-config
のインストールなどいろいろ面倒なのでWSLのUbuntu環境をGoの実行環境にしたいと思います。
また、今回はGoのOracle接続ライブラリとしてmattn/go-oci8を利用します。
参考にしたのはこちら
2.1 各種インストール
まずは必要なライブラリとGo1.18をインストールします。
# その他依存ライブラリのインストール
$ sudo apt update && apt upgrade -y
$ sudo apt-get install curl unzip pkg-config git
# Go 1.18のインストール
$ sudo add-apt-repository ppa:longsleep/golang-backports
$ sudo apt install golang-1.18
インストール後各種環境変数の設定を.bash_profile
に追記します。
export PKG_CONFIG_PATH=/usr/lib/pkgconfig/
export GOPATH=~/go
export GOROOT=/usr/lib/go-1.18
export PATH=$GOROOT/bin:$PATH
2.2 Oracle Instant Clientのダウンロード
Oracle Instant Client Downloadsから自分の環境にあったクライアントをダウンロードします。
こちらのファイルのダウンロードにOracleアカウントは不要となります。
「Linux x86-64 (64-bit)」の下記をダウンロードします。
- Basic Package
- SDK Package
バージョンは執筆時点最新の「Version 21.7.0.0.0」を選択し/usr/local
ディレクトリにダウンロードしたファイルを解凍します。
$ curl -s -o instantclient-basic-linux.x64-21.7.0.0.0dbru.zip https://download.oracle.com/otn_software/linux/instantclient/217000/instantclient-basic-linux.x64-21.7.0.0.0dbru.zip
$ curl -s -o instantclient-sdk-linux.x64-21.7.0.0.0dbru.zip https://download.oracle.com/otn_software/linux/instantclient/217000/instantclient-sdk-linux.x64-21.7.0.0.0dbru.zip
$ ll | grep instantclient
instantclient-basic-linux.x64-21.7.0.0.0dbru.zip
instantclient-sdk-linux.x64-21.7.0.0.0dbru.zip
$ sudo unzip instantclient-basic-linux.x64-21.7.0.0.0dbru.zip -d /usr/local
$ sudo unzip instantclient-sdk-linux.x64-21.7.0.0.0dbru.zip -d /usr/local
/usr/local
にファイルを配置できたら、環境変数にLD_LIBRARY_PATH
を設定するため.bash_profile
に設定を追記します。
export LD_LIBRARY_PATH=/usr/local/instantclient_21_7
最後に.bash_profile
の再読み込みを実行します。
$ source ~/.bash_profile
2.3 oci8.pcファイルの作成
下記ファイルを/usr/lib/pkgconfig/
に格納する。
prefix=/usr/local/instantclient_21_7
libdir=${prefix}
includedir=${prefix}/sdk/include/
glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums
Name: oci8
Description: oci8 library
Libs: -L${libdir} -lclntsh
Cflags: -I${includedir}
Version: 12.2
とりあえずこれでoci8利用に向けた準備作業はOK。
3. Goアプリの実装
次に肝心のGoアプリを実装します。
3.1 アプリの実装
正直実装は↓の方コードを〇パクリです。
確認したいのはDockerイメージビルド時のociの扱いについてなので細かいアプリの中はどうでもいいです。
package main
import (
"database/sql"
"log"
_ "github.com/mattn/go-oci8"
)
func main() {
connectStr := "gouser/pwd@localhost:1521/GOPDB"
db, err := sql.Open("oci8", connectStr)
if err != nil {
log.Printf("DbOpen Error: %s", err)
return
}
defer db.Close()
// 以下のようにクエリ投げる
rows, err := db.Query("SELECT USER_ID, USER_NAME FROM SAMPLE_USER")
if err != nil {
log.Printf("Query Error: %s", err)
return
}
defer rows.Close()
// 以下のようにデータを取得する
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
log.Printf("ID: %d Name: %s", id, name)
}
}
3.2 テスト用テーブルとデータの作成
動作確認用のテーブルとしてsample_user
テーブルとテストデータをOracleに登録します。
SQLの流し方はA5M2を使うも、コンテナに入ってからsqlplusで流すも好きな方法を利用してください。
CREATE TABLE sample_user (
user_id VARCHAR2(10) NOT NULL,
user_name VARCHAR2(30) NOT NULL,
user_age NUMBER(3, 0) NOT NULL,
CONSTRAINT pk1 PRIMARY KEY(user_id)
);
INSERT INTO sample_user (user_id, user_name, user_age) VALUES ('00001', 'testuser01', 20);
INSERT INTO sample_user (user_id, user_name, user_age) VALUES ('00002', 'testuser02', 25);
INSERT INTO sample_user (user_id, user_name, user_age) VALUES ('00003', 'testuser03', 40);
3.3 動作確認
最後にGoアプリの動作確認です。
とりあえず、プロジェクト(main.go
しかないですが)をビルドして生成されたバイナリを実行します。
$ go mod download
$ go build -o go-sample
$ ./go-sample
2022/09/13 23:49:43 Version:default/Revision:dev
2022/09/13 23:49:43 ID: 1 Name: testuser01
2022/09/13 23:49:43 ID: 2 Name: testuser02
2022/09/13 23:49:43 ID: 3 Name: testuser03
無事Oracleからユーザ情報を取得してログに出力することができました。
とりあえず動くところまでは来たので今回はここまでとします。
に続く。