blog

mybatis ------ ダイナミックSQL

例では、前のいくつかのブログでは、mybatisとテーブルのCRUD操作について説明しますが、SQLステートメントは、比較的単純であることがわかった、より複雑なビジネスがある場合は、複雑なSQLステー...

Jan 6, 2021 · 7 min. read
シェア

例では、前のいくつかのブログは、mybatisとテーブルのCRUD操作について説明しますが、SQLステートメントは、比較的単純であることがわかったが、より複雑なビジネスがある場合は、複雑なSQLステートメントを記述する必要がある、多くの場合、スプライシングする必要があり、SQLをスプライシング、少し不注意、転置カンマ、スペースなどがないため、エラーにつながる可能性があります。

では、どうやってこの問題を解決するのでしょうか?これはmybatis動的SQLの使用です、if、choose、when、otherwise、trim、where、set、foreachおよびその他のタグは、非常に柔軟なSQL文に組み合わせることができ、同時にSQL文の精度を向上させるだけでなく、大幅に開発者の効率を向上させます。

Userテーブルを例にとってみましょう:

動的SQL:if

ユーザー名と性別に基づいてデータを照会します。username が null の場合は、sex のみに基づいてクエリを実行します。それ以外の場合は username のみに基づいてクエリを実行します。

まず第一に、ダイナミック SQL を使って

<select id="selectUserByUsernameAndSex" 
		resultType="user" parameterType="com.ys.po.User">
	<!-- ここで、通常のSQLクエリステートメントとほとんど同じである。#{id}プレースホルダは、必ずしもidである必要はない。,
			書きたいことは何でも書くが、空白のままにしないこと。 パラメータが複数ある場合は、pojo クラスの属性を書かなければならない。>
	select * from user where username=#{username} and sex=#{sex}
</select>

上記のクエリ文では、#{ユーザー名}が空の場合、クエリ結果も空であることがわかります。ifを使って判断します。

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
	select * from user where 
		<if test="username != null">
		 username=#{username}
		</if>
		
		<if test="username != null">
		 and sex=#{sex}
		</if>
</select>

sexがnullの場合、select * from user where username=#{username}となりますが、usernameがnullの場合、select * from user where and sex=#{sex}となります。この場合、クエリステートメントはselect * from user where and sex=#{sex}となります。以下のwhere文を見てください。

動的SQL:if+where

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
	select * from user 
	<where>
		<if test="username != null">
		 username=#{username}
		</if>
		
		<if test="username != null">
		 and sex=#{sex}
		</if>
	</where> 
</select>

where」タグは、それが含むタグのいずれかが戻り値を持つ場合、「where」を挿入することを知っています。さらに、タグがANDまたはORで始まるものを返す場合は、それを取り消します。

動的SQL:if+set

同様に、上記のクエリSQLステートメントにwhereキーワードが含まれている場合、更新操作で、setキーワードが含まれている場合、どのようにそれを扱うのですか?

<!-- idに基づいてuserテーブルを更新する>
<update id="updateUserById" parameterType="com.ys.po.User">
	update user u
		<set>
			<if test="username != null and username != ''">
				u.username = #{username},
			</if>
			<if test="sex != null and sex != ''">
				u.sex = #{sex}
			</if>
		</set>
	
	 where id=#{id}
</update>

動的SQL:choose(when,otherwise)

時には、すべてのクエリ条件を使用するのではなく、クエリ条件の1つだけを選択したい場合があります。

<select id="selectUserByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
	select * from user 
	<where>
		<choose>
			<when test="id !='' and id != null">
				id=#{id}
			</when>
			<when test="username !='' and username != null">
				and username=#{username}
			</when>
			<otherwise>
				and sex=#{sex}
			</otherwise>
		</choose> 
	</where>
</select>

つまり、id,username,sexの3つの条件がありますが、クエリー条件として選択できるのは1つだけです。

idがNULLでない場合、クエリ文は次のようになります: select * from user where id=?

ユーザー名がNULLの場合、クエリはselect * from user where sex=?

動的SQL:trim

trimタグは、setタグやwhereタグの機能を果たすフォーマットタグです。

上の2番目の箇条書きのif+where文を書き換えるにはtrimを使います。

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
	select * from user 
	<!-- <where>
		<if test="username != null">
		 username=#{username}
		</if>
		
		<if test="username != null">
		 and sex=#{sex}
		</if>
	</where> -->
	<trim prefix="where" prefixOverrides="and | or">
		<if test="username != null">
		 and username=#{username}
		</if>
		<if test="sex != null">
		 and sex=#{sex}
		</if>
	</trim>
</select>

prefix: 接頭辞

prefixoverride: 最初の and または を削除します。

トリムを使って、上記3の if+set ステートメントを書き換えます。

<!-- idに基づいてuserテーブルを更新する>
<update id="updateUserById" parameterType="com.ys.po.User">
	update user u
		<!-- <set>
			<if test="username != null and username != ''">
				u.username = #{username},
			</if>
			<if test="sex != null and sex != ''">
				u.sex = #{sex}
			</if>
		</set> -->
		<trim prefix="set" suffixOverrides=",">
			<if test="username != null and username != ''">
				u.username = #{username},
			</if>
			<if test="sex != null and sex != ''">
				u.sex = #{sex},
			</if>
		</trim>
	
	 where id=#{id}
</update>

suffix: 接尾辞。

suffixoverride: 最後のコンマを削除します。

動的SQL: SQL

コードの再利用性を高め、コードを簡素化するために、これらのコードを抽出し、直接呼び出しを使用する必要があります。

例:ユーザー名と性別に基づいた共同クエリを頻繁に実行する必要がある場合、次のようにコードを抽出します:

<!-- sql フラグメントを定義する>
<sql id="selectUserByUserNameAndSexSQL">
	<if test="username != null and username != ''">
		AND username = #{username}
	</if>
	<if test="sex != null and sex != ''">
		AND sex = #{sex}
	</if>
</sql>

SQLフラグメントの引用

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
	select * from user 
	<trim prefix="where" prefixOverrides="and | or">
		<!-- sql フラグメントを参照するには、refid がこのファイルにない場合、namespace -- を先頭に追加する必要がある。>
		<include refid="selectUserByUserNameAndSexSQL"></include>
		<!-- また、ここで参照できる他のSQLフラグメントもある。>
	</trim>
</select>

注釈 ①、フラグメントの再利用性を高めるには、1 つのテーブルを基に sql フラグメントを定義するのが最善です。

SQLフラグメントにwhereを含めない方が良いでしょう。

動的SQL: foreach

要件: ユーザーの1,2,3について、それぞれユーザーテーブルのIDをクエリする必要があります。

SQLステートメント: select * from user where id=1 or id=2 or id=3

select * from user where id in

リストids属性をカプセル化したUserVoクラスを作成します。

package com.ys.vo;
import java.util.List;
public class UserVo {
	//複数のユーザIDをカプセル化する
	private List<Integer> ids;
	public List<Integer> getIds() {
		return ids;
	}
	public void setIds(List<Integer> ids) {
		this.ids = ids;
	}
} 
<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
	select * from user 
	<where>
		<!--
			collection:入力オブジェクトでコレクション属性を指定する
			item:生成されたオブジェクト
			open:トラバーサル開始時に文字列をスプライスする
			close:最後にスプライスされた文字列
			separator:オブジェクト間でスプライスする必要がある文字列を繰り返し処理する。
			select * from user where 1=1 and (id=1 or id=2 or id=3)
		 -->
		<foreach collection="ids" item="id" open="and (" close=")" separator="or">
			id=#{id}
		</foreach>
	</where>
</select>

テスト:

//id コレクションに従って user テーブルを照会る
@Test
public void testSelectUserByListId(){
	String statement = "com.ys.po.userMapper.selectUserByListId";
	UserVo uv = new UserVo();
	List<Integer> ids = new ArrayList<>();
	ids.add(1);
	ids.add(2);
	ids.add(3);
	uv.setIds(ids);
	List<User> listUser = session.selectList(statement, uv);
	for(User u : listUser){
		System.out.println(u);
	}
	session.close();
}

foreachを使用して、select * from user where id in を次のように書き換えます。

<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
	select * from user 
	<where>
		<!--
			collection:入力オブジェクトでコレクション属性を指定する
			item:生成されたオブジェクト
			open:トラバーサル開始時に文字列をスプライスする
			close:最後にスプライスされた文字列
			separator:オブジェクト間でスプライスする必要がある文字列を繰り返し処理する。
			select * from user where 1=1 and id in (1,2,3)
		 -->
		<foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
			#{id}
		</foreach>
	</where>
</select>

以下は、mybatis に期待できることの要約です。

実際、動的SQL文の作成はしばしばスプライシングの問題になります。スプライシングが正確であることを保証するためには、まずネイティブなSQL文を書き出し、その変更に対してmybatis動的SQLを通してエラーを防ぐのが最善です。

Read next

SpringでRedisを使う

redis接続ドライバは、現在最も使用されているJedisでなければなりません。 springは、インターフェイスオブジェクトを生成することができますインターフェイスを提供し、インターフェイスオブジェクトは、Rediisの基本的なインターフェイスのパッケージです...

Jan 6, 2021 · 6 min read