--
--

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Tag:

06
2010

[Java]MyBatisを使ってみた(3.0.2)

CATEGORYJava
しばらく前からiBatis・・・じゃなくて今はMyBatis、の使い方を調べてた。
が、日本語の情報があんまり無い感じだったので、ちょっと簡単に書いてみる。
(iBatis2の情報はいっぱいあるけど微妙に異なる。iBatis3は同じっぽい?がそもそも情報自体が少ない。)

基本的には英語の公式ドキュメントでカバーできそう。
以下、そこから抜き出しただけだけのものも含む。大まかにしか読めてないので、間違って解釈してたらすいません(--;
また、iBatisの使用経験はないため、ここが変わった・・・等の話も判りませんのであしからず。

XML構成ファイル

まずDB接続やトランザクションといった全体の設定を記述するためのXML構成ファイルを作成する。
ファイル名は任意。デフォルトは Configuration.xml?
普通にJDBCで繋ぐ例は公式ドキュメントの冒頭にあるので、データソースをJNDIからとって、トランザクション管理にJTAを用いる例を。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="production">
<environment id="production">
<transactionManager type="MANAGED">
<property name="UserTransaction" value="javax.transaction.UserTransaction" />
</transactionManager>
<dataSource type="JNDI">
<property name="data_source" value="hoge" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="foo/dao/mapper/MemberMapper.xml" />
</mappers>
</configuration>
WebLogic 10.3上のWebアプリで、とりあえずこれで動作することを確認(ただしnot EJBなアプリ)。
dataSourceを自前でやる場合は、プールさせたりいろいろと指定ができるみたい。
mapper欄は、この次のマッピングファイルのパスを記述する。
ここはファイルが増えるごとに一々書いていかないといけないようだ。

なお、設定ファイルを用いずプログラム上で直接指定することもできる模様(一応は)。

XMLマッピングファイル

MyBatisの肝と思われる部分。SQL文とオブジェクトのマッピングをXMLファイルに記述する。
以下、下記のようなテーブルをイメージして、単純な例をいくつか(Java側にも同じようなbeanクラスがあるイメージ)。
CREATE TABLE MEMBERS
(
MEMBER_ID NUMBER(9),
NAME VARCHAR2(100),
STATUS NUMBER(1)
);
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="foo.dao.mapper.MemberMapper">
<!-- プロパティと列名のマッピング -->
<resultMap id="memberResultMap" type="foo.model.Member">
<id property="memberId" column="MEMBER_ID" />
<result property="name" column="NAME" />
<result property="status" column="STATUS" />
</resultMap>

<!-- 全検索 -->
<select id="select" resultMap="memberResultMap">
SELECT * FROM MEMBERS
</select>

<!-- IDで検索 -->
<select id="selectById" parameterType="int" resultMap="memberResultMap">
SELECT * FROM MEMBERS WHERE MEMBER_ID = #{memberId}
</select>

<!-- 件数カウント -->
<select id="countByName" parameterType="String" resultType="int">
SELECT COUNT(*) FROM MEMBERS WHERE NAME LIKE '%' || #{name} || '%'
</select>

<!-- 登録 -->
<insert id="insert" parameterType="foo.model.Member">
INSERT INTO MEMBERS (MEMBER_ID, NAME)
VALUES (#{memberId}, #{name})
</insert>

<!-- 更新 -->
<update id="update" parameterType="foo.model.Member">
UPDATE MEMBERS
SET
NAME = #{name},
STATUS = #{status}
WHERE MEMBER_ID = #{memberId}
</update>

<!-- 削除 -->
<delete id="delete" parameterType="int">
DELETE FROM MEMBERS
WHERE MEMBER_ID = #{memberId}
</delete>
</mapper>
※ DBはOracleをイメージ。適時読み替えてください。

だいたい見たまま。検索結果をモデルで取得したいときは、resultMapにモデルと列名の対応を定義しておいて、SELECTタグにそれを指定。
パラメータとして渡すときはモデルをそのまま指定、プロパティ名を記述すればよいようだ。
もちろんintやStringで取ったり渡したりもできる(Mapも可のはず)。

公式ドキュメントによると、XMLファイルを用いずインタフェースを作成してそこにアノテーションで同じようにマッピングを記述していくことも出来るようで、どうもそれを強化していこうとしているような雰囲気を感じる
(この次のSQLの実行の部分が、キャストが不要になったり、namespaceをコードで指定できたりと改善されている。)
でも、MyBatisを使うような人は初めからXMLファイルに集約するつもりだと思うので、誰得なのかよく判らない。
今回はパス。

SQLの実行

次に、上で定義したSQLの呼び出し部分。以下抜粋。
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("Configuration.xml"));
SqlSession session = sqlSessionFactory().openSession();
Member member;
try {
member = (Member) session.selectOne("foo.dao.mapper.MemberMapper.selectById", memberId);
} finally {
session.close();
}
・・・今時キャストが必要なのはいけてない気がするけど致し方ないようだ。
SqlSessionFactoryはシングルトンとかにして使いまわしていい模様。

他にもいろいろなメソッドがあるが、流れ的にはだいたい同じような感じで、SqlSessionを取得して実行するだけなのでソースは割愛。
使いそうなメソッドだけ簡単に説明を。

メソッド用途備考
Object selectOne(String statement, Object parameter)1レコードを取得するSELECT文実行公式ドキュメントには結果が無い場合例外を投げる (If any more than one, or none (null) is returned, an exception will be thrown.) とあるように見えるが、3.0.2現在投げない?
Object selectOne(String statement)
List selectList(String statement, Object parameter)複数レコードを取得するSELECT文実行 
List selectList(String statement)
List selectList
(String statement, Object parameter, RowBounds rowBounds)
ページング用?動作未確認。
int insert(String statement, Object parameter)INSERT文実行 
int insert(String statement)
int update(String statement, Object parameter)UPDATE文実行 
int update(String statement)
int delete(String statement, Object parameter)DELETE文実行 
int delete(String statement)
void commit()コミット自前でトランザクション管理を行う場合。
void rollback()ロールバック

トランザクション

SQLの実行自体は特に迷うことも無いと思われるが、トランザクション周りについて。
メソッド定義的にも伝わってくるが、自前でトランザクション管理を行う場合、SqlSessionを使い回さざるを得ないようだ。
この辺りはそのままでは使い勝手が悪いので、通常はDIコンテナやJTAと組み合わせて対応することになると思う。
(自分のところはJTAが使える環境だったのでそれを使う形で回避した。)

公式には Spring, guiceと連携させるためのライブラリが用意されている。
Springについては未確認。
guiceについては、現状の1.0.0RC3ではアノテーションで書くやり方でないとトランザクション管理できないようで、使い物にならなかった(泣
(出来るのかもしれないが、SqlSessionFactoryを使わず、自分であれこれしないと駄目な模様?)


動的な検索

ここまででSQLを流すまでは完了・・・だが、動かせるようになった後に気になる部分ということで、検索条件を動的に指定する方法も書いておく。
<select id="selectByCondition" parameterType="Map" resultMap="memberResultMap">
SELET * FROM MEMBERS
WHERE memberId > 100
<if test="name != null">
AND NAME LIKE '%' || #{name} || '%'
</if>
<if test="status != null">
AND STATUS IN
<foreach item="flag" collection="status"
open="(" separator="," close=")">
#{flag}
</foreach>
</if>
</select>
ifやforeachといったタグで、パラメータの有無によってSQLを変更したり、繰り返し項目を出力することが可能。
この例は手抜き(汗 なので入れていないが、WHERE句が不要になる場合も想定したwhereタグや、余ったANDを消すためのtrimといったタグもある模様(いずれも未確認)。

ソート条件を指定するような場合は、
ORDER BY ${columnName}
のように指定することで、動的にSQL文に文字を含めることも出来るとのこと(こちらも未確認)。
ただし、当然のことながらSQLインジェクションの警戒が必要になる。

シーケンスでの採番

この辺でとりあえず最低限絶対必要と思われる話は終了、ネタ切れ。おまけで、INSERT時にシーケンス等で採番する方法も調べたので書いておく。
<insert id="insert" parameterType="foo.model.Member">
<selectKey keyProperty="memberId" resultType="int" order="BEFORE">
SELECT MEMBER_ID_SEQ.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO MEMBERS (MEMBER_ID, NAME)
VALUES (#{memberId}, #{name})
</insert>
こんな感じでINSERT前にSQLを投げ、トリガーなどを用いず、mybatisだけで採番することが可能。


何か結構長くなったけど、以上、MyBatis調べてる人の参考・・・とっかかりになれば幸いです。
その他、重要そうな機能としてページングとキャッシュがあるけれど、調べる時間が無くなったので今回は確認できず。
ページングはselectListのRowBoundsを指定してやればいいのかな?性能的にどうなのかとかちょっと心配だけれど・・・。

というか、公式ドキュメントにはここには書いてない機能が山ほど載っているので、何はともあれ一度は上から下までさーっと目を通すべき。英語・・・と中国語版しかないけど(--


2011/1/10追記
続き1, 続き2

インタフェース周りについて大きな勘違いをしていました(取消線の辺り)
続き2で訂正していますので、あわせて参照ください。

スポンサーサイト

Tag: Java MyBatis

0 Comments

Leave a comment

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。