前回は Go で簡単なWebサーバを作成しました。
今回からはデータベース操作を行っていきます。
データベースの準備
今回はデータベースサーバに H2 を使います。 H2 は postgres プロトコル互換モードがあるので、postgres 用のドライバで接続できます。
H2 は単一 jar を java -cp
で起動すれば使えますが、ここではダウンロードから起動までの操作も Go で書いてみます。
ファイルのダウンロード
ファイルの取得は http.Get(url)
でできます。
以下のような流れになります。
out, err := os.Create(path) resp, err := http.Get(url) n, err := io.Copy(out, resp.Body)
出力対象のファイルを作成し、Get で取得したレスポンスをファイルにコピーします。
全体は以下のようになります。
func download(url string, path string) error { out, err := os.Create(path) if err != nil { return err } defer out.Close() resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() if _, err := io.Copy(out, resp.Body); err != nil { return err } return nil }
defer
は java での finally のようなものです。メソッドを抜ける時に定義したのと逆順で処理が実行されます。
主にリソースの開放などに使われます。注意点としてはループ処理の中で defer
を定義してはいけない点です。
if
はセミコロンで区切ることで、条件句以外に文を書くことができます。
io.Copy()
の結果として err
を受け取り(第一戻り値は無視)、err
の有無を条件式で判定しています。
コマンドの実行
H2 をダウンロードして実行します。
コマンドの実行は exec.Command()
を使います。
const ( url = "http://central.maven.org/maven2/com/h2database/h2/1.4.194/h2-1.4.194.jar" path = "lib/h2-1.4.194.jar" ) func startH2() { if _, err := os.Stat(path); os.IsNotExist(err) { os.MkdirAll(filepath.Dir(path), 0755) if err := download(url, path); err != nil { panic(err) } } cmd := exec.Command("java", "-cp", path, "org.h2.tools.Server") cmd.Start() time.Sleep(3 * time.Second) log.Printf("PID[%v]", cmd.Process.Pid) }
最初にファイルの存在チェックを行い、ファイルが無ければダウンロードしています。
失敗時には panic()
でアプリケーションを終了します。
その後、コマンドを実行します。cmd.Run()
とすると処理の終了を待ちますが、ここでは cmd.Start()
でコマンドの終了を待たずに処理を進めます。
H2 のストップは以下のコマンドで行います。
func stopH2() { err := exec.Command("java", "-cp", path, "org.h2.tools.Server", "-tcpShutdown", "tcp://localhost:9092").Run() if err != nil { log.Fatal(err) } }
まとめ
ここまでの全体像は以下となります。
package main import ( "log" "os" "net/http" "io" "os/exec" "path/filepath" "time" ) const ( url = "http://central.maven.org/maven2/com/h2database/h2/1.4.194/h2-1.4.194.jar" path = "lib/h2-1.4.194.jar" ) func download(url string, path string) error { out, err := os.Create(path) if err != nil { return err } defer out.Close() resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() if _, err := io.Copy(out, resp.Body); err != nil { return err } return nil } func startH2() { if _, err := os.Stat(path); os.IsNotExist(err) { os.MkdirAll(filepath.Dir(path), 0755) if err := download(url, path); err != nil { panic(err) } } cmd := exec.Command("java", "-cp", path, "org.h2.tools.Server") cmd.Start() time.Sleep(3 * time.Second) log.Printf("H2 Started. PID[%v]", cmd.Process.Pid) } func stopH2() { err := exec.Command("java", "-cp", path, "org.h2.tools.Server", "-tcpShutdown", "tcp://localhost:9092").Run() if err != nil { log.Fatal(err) } } func main() { startH2() stopH2() }
データベースの起動と停止ができたので、次回でデータベースへのアクセスを行います。