kazu22002の技術覚書

PHPer, Golang, AWS エンジニアの日々

golangとxormとoracle ~ AutoIncrementとJoin ~

golangでの開発は楽しいですね。最近ひたすら書いている気がします。

その中でoracleを使う開発があり、かなり困ったことがあったので、解決案を書いてみようと思います。

xorm

github.com

ORMを利用するために選んだライブラリです。oracleがexperimentでも一応あるとのことで試してみたライブラリです。

oracleを使う場合に、触ってみて動作しないと思った部分です。

  • Insertのauto incrementのIDの取得ができない
  • Getで単体データを取得する際にJoinができない

ほかのDBであれば、問題なくできるところですが、oracleの書き方が特殊すぎるために難しいんでしょうね。

auto incrementが取得できない

個人的にoracleにまったく詳しくない状態で、調べているので書くことがおかしい可能性は高いですが、取れなかったのでいろいろと調べました。

res, err := session.queryBytes("select seq_atable.currval from dual", args...)

この部分で登録したIDを取得していると思いますが、どうやらうまく取得できないみたいです。

xormでoracleを使う場合、mattnさんのgo-oci8を使用します。

github.com

mattnさんのexampleをみてみると、lastinsertIdを取得するサンプルがあるので、参考にして取得できるようにしてみます。

        session := SqlHandler.NewSession();
    res, err := session.Exec("INSERT USERS (NAME) VALUES ('test')")
    if err != nil {
        return err
    }
    //追加したIDを取得(ORACLEの場合はテーブルのIDでは無く最終の何かのIDが取得できる そこからROWIDを取得
    lastInsertId, _ := res.LastInsertId()
    RowId := *(*string)(unsafe.Pointer(uintptr(lastInsertId)))

    sqlorargs = []interface{}{}
    sqlorargs = append(sqlorargs, "SELECT ID FROM USERS WHERE ROWID = :1")
    sqlorargs = append(sqlorargs, RowId)

    results, err := session.Query(sqlorargs...)

    idByte := results[0]["ID"]
    id, err := strconv.ParseInt(string(idByte), 10, 64)
    if err != nil || id <= 0 {
        return err
    }

    m.ID = id

テーブルを明示的に設定する必要がありますが、SQLの部分さえxormで作成できるようになれば、ORMを利用してauto incrementのIDも取得できるようになります。

SQL作成も一応自作しましたが、xormを部分的にコピーして作成したので必要な部分のみで頑張れる感じです。

ちなみにモデルとして、構造体を作成する際にIDをreadonlyにしておかないと、IDのカラムを付与して登録する可能性もあるため、readonlyにしています。

type USERS struct {
    ID   int64 `xorm:"ID <- pk"`
    NAME string `xorm:"NAME"`
}

oracleのauto incrementの設定でIDを自分で登録するかどうかも設定できますが、IDを自分で登録する必要はないため、設定できないようにしていたほうがいいと思います。

Join

これは、oracleにLIMITがないため発生していると思います。

行を制限して取得するために、サブクエリを駆使して取得するため、複数テーブルになるとカラムがバッティングする可能性があるため、エラーになる可能性が高くなっています。

カラム名が同じでなければ大丈夫でしょうが、現実的に無理なので検討する必要すらないですね。

取得行を指定するためにROWIDで範囲を指定する必要があるとか、大変ですねー。oracleもう辞めようよー。

対策としては、Findで取得した後に、範囲を自分で取得するようにしています。

DBで取得する時点で制限させてほしいですね。難しいです。

oracle大変すぎる

oracle特有の部分が多くて大変です。ライブラリ側も対応するのが大変だと思います。

今の時代になぜoracleを選択するのか本当にわからないです。

ライセンスとして有料であり、ここまで開発することが大変なDBを選択する理由はなんだろうか。

まぁ、お金を使うために選択したいなら文句は言えないけど、少し調べればサービスのためかける選択をもっと意味のある部分に力を使えると思います。

もっとお金のためでなく、世の中をよくするためにどういう選択肢を提示するのがいいか考えて欲しいです。

サポートがあるのがいい。というが、なんのサポートを期待してるのかな。

世の中は色々難しいですね。