記憶のくずかご

メモを書く 適当に書く まじめに書かない

JPA with HibernateとMyBatisのどちらを採用すべきか

会社で書いたメモを貼る。

割とまじめに書いたけどもうこういうことはやめよう。長続きしないから。

下の文章見て思ったことはJava側でデータ操作するなって書いたけど、ストアドプロシージャを使えってことではないので。MyBatisでストアドプロシージャはあまり使わない方がいいと思う。移植性悪くなるから。

あと、これは一つの意見なので別にHibernateを選んでもいいと思う。おわり。


最初に結論を言うと、私はMyBatisを採用すべきだと考えています。もちろんcase by caseなのでどのような場合にもMyBatisが良いわけではありません。ただ、たいていの場合はMyBatisを選ぶ方が良いと考えます。

MyBatisを選ぶ理由は2つです。

  1. ほぼ生のSQLを記述でき、透明性がある
  2. Hibernateを長期運用した際のデメリットがメリットを上回る

要するにHibernateがダメだからです。

では、なぜHibernateがダメかと言うと下記の2つの理由があります。

  1. 自動生成されるテーブルや発行されるSQLブラックボックス化されている
  2. 学習コストが高い

逆に言うと、これらのデメリットを解決できればHibernateを採用しても良いと考えます。

理由の1つ目のブラックボックス化ですが、生成されるテーブルにこだわりがなく、発行されるSQLが多少冗長でも問題なければ採用しても良いと思います。単純なデータしか持たないアプリケーションであればHibernateを使うことで生産性は上がります。

理由の2つ目の学習コストですが、開発チーム内にHibernateについて熟知している人がいれば問題ありません。熟知しているとは、N+1問題が発生するから関連をなくしてJOINしなくて済むテーブル構成にしよう、などと言う人のことではありません。適切にN+1問題を解決でき、どういう場合に思い通りのSQL文が発行されるかを把握しており、Hibernateで問題が発生したときに適切に解決できる人のことです。そういう人がいなければHibernateを採用すべきではないと思います。

Hibernateのメリット

Hibernateのメリットとは何でしょうか。おそらく下記のようなものだと思います。

  1. SQL文を書かなくて済む
  2. RDBMSに依存しないため移植性が上がる

1つ目のメリットは確かにその通りだと思います。ただし、SQLを知らなくて良いかと言われるとそういうわけではありません。SQLを知っていないとHibernateは使いこなせません。基本的にJPAを使うのであればJPQLを使用することになると思いますが、JPQLはSQLに似ているため、ほとんどSQLを書くようなものです。もちろんJPQLを使わないで済む単純なデータしか持っていないのであれば、JPQLすら書かなくて済むでしょうが。

2つ目がHibernateを利用する最大のメリットだと思います。しかし、このメリットは他の代替手段でカバーすることができます。それは、RDBMSに依存しないSQL文を書くことです。

したがって、SQLに十分詳しく、方言を使用しないSQL文を書けるのであればHibernateを使うメリットはあまりないと思います。

人口比

Hibernateに精通している人とSQLに精通している人のどちらが多いでしょうか。普通に考えればSQLに精通している人の方が多いと思います。また、今後のキャリアやスキルアップを考えた場合、Hibernateに精通したいかSQLに精通したいかといえば、SQLに精通したいと多くの人は考えるのではないでしょうか。

ソフトウェアは作れば終わりではありません。今後何年間も保守・運用していかなければなりません。保守・運用を考えた場合、人が入れ替わり立ち替わりしても確保しやすい人材が必要です。HibernateSQLのどちらが保守・運用しやすいでしょうか。

設計方針の違い

Hibernateのデメリットにブラックボックス化というのがありますが、良い言い方をすると抽象化です。これはHibernateの設計思想に表れています。

O/R Mapperを設計する場合重要なのは何を解決したいかです。HibernateはO/RのObject側を優先して設計しています。一方、MyBatisはRelational側を優先して設計しています。

Object側を優先した設計とは、Object側の設計や関連(One to One, One To Many, Many to One, Many to Many)が最も重要で、永続化の手段はどうでも良いということです。つまり、RDBでなくても、ファイルでもNoSQLでも何にどうやって永続化するかは関心がありません。これは一見すると良い設計ですが、現実的には違います。なぜなら、RDBの場合、パフォーマンスに大きく影響するからです。先ほどの永続化手段の無関心さは、悪い言い方をすると、冗長なテーブル構成になろうが、SQL文が何回発行されようがどうでも良いということになります。もちろんHibernateには冗長なテーブル構成を防ぐ手段もN+1問題を解決する手段もありますが、そのためにはHibernateについて熟知する必要があります。

一方、Relational側を優先した設計とは、DBのテーブルありきの設計です。既に出来上がったテーブルに合わせてデータをオブジェクトにマッピングします。したがって、Object側の関連が多少おかしかろうが、そんなものには関心がないということです。もちろんMyBatisにもObject側の関連を解決する手段がありますが、Hibernateほど簡単にはマッピングできません。

この設計思想の違いにおいても、HibernateとMyBatisのどちらを採用すべきかが見えてきます。パフォーマンスを考え、テーブル構成をきちんと定義し、複雑なSQL文を発行したいのであればMyBatisを使った方が良いでしょう。単純なデータを扱い、パフォーマンスよりも生産性を優先するのであればHibernateの方が良いと思います。

ただし、今後の拡張性を考えるとテーブル構成をきちんと定義した方が良いと思います。データは振る舞いに比べ変更は多くありません。また、複雑なSQL文を発行できる方がメリットが大きいです。DBでできる操作はDBでやらないとRDBを採用する意味がありません。RDBを使うのであればJava側(ビジネスロジック側)でデータ操作をするのはできる限り避けるべきです。

まとめ

最初に述べたように私は基本的にMyBatisを採用すべきだと考えています。

ただし、case by caseなのでどちらが開発により適しているかを考えた方がよいと思います。そして、保守・運用の面でもどちらがより有効かどうかを考慮に入れるべきです。

参考文献

http://blogs.wankuma.com/oakbow/archive/2010/08/12/192280.aspx
http://tech.a-listers.jp/2011/06/16/orm_is_an_antipattern/
http://s2container.seasar.org/2.4/ja/s2jdbc_abstract.html