LoginSignup
2
1

More than 3 years have passed since last update.

Doma2で前方一致検索をしたい場合は@prefixを活用する。

Posted at

自分がかかわっているシステム開発プロジェクトで、他のチームがこのことでえらく盛り上がっていたので、自分なりに調べた結果を残しておきたいと思います(´・ω・`)

前提

商品在庫を管理するシステム(Java + Doma2)を構築するにあたって、ユーザ入力値をもとに商品名を前方一致で検索したいという要件があったとします。

この要件を実現するため、とある開発者が実施したことは、まず以下のような2-way SQL (findLikeName.sql)を用意することでした。

findLikeName.sql
SELECT *
  FROM product
 WHERE name LIKE /* name */'みかん%'

これを以下のような形で呼び出すわけですね。

String name = "りんご"; // ユーザの入力した値
name += "%";
List<Product> products = productDao.findLikeName(name);
doSomething(products);

この場合、以下のようなクエリが発行されるので、要件が実現できているように見えます。

SELECT *
  FROM product
 WHERE name LIKE 'りんご%'

問題点

たとえばユーザ入力値が%だったとします。

String name = "%"; // ユーザの入力した値
name += "%";
List<Product> products = productDao.findLikeName(name);
doSomething(products);

この場合、以下のようなSQLが実行されます。

SELECT *
  FROM product
 WHERE name LIKE '%%'

このクエリはnameがnull以外の行にヒットしてしまいます。これでは%で商品名を前方一致検索したいという要件にこたえられていないだけでなく、セキュリティ上の問題を発生させる可能性すらあります。

修正方法

この解決策としてはExpression language@prefixを利用することです。

今回の場合はまずfindLikeName.sqlを以下の通りに修正します。

findLikeName.sql
SELECT *
  FROM product
 WHERE name LIKE /* @prefix(name) */'みかん%'

その後呼び出し方を以下のように修正します。

String name = "りんご"; // ユーザの入力した値
List<Product> products = productDao.findLikeName(name);
doSomething(products);

@prefixは入力パラメタを前方一致検索用の文字列に変換してくれるだけでなく、%_のような特別な意味を持つ文字をエスケープしてくれる関数です。そのため、パラメタとして%が渡されたとしても安心ということですね。

環境情報 (pom.xmlから抜粋)

pom.xml
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.seasar.doma.boot</groupId>
    <artifactId>doma-spring-boot-starter</artifactId>
    <version>1.5.0</version>
</dependency>
<dependency>
    <groupId>org.seasar.doma</groupId>
    <artifactId>doma-processor</artifactId>
    <version>2.30.0</version>
    <scope>provided</scope>
</dependency>
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1