1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MybatisでNull判定するときのNullは大文字ではなく小文字で!!

Last updated at Posted at 2022-08-30

初めに

Mybatisを使用して、SQLのWEREE条件にNullチェックをした際に下記のようなエラーではまりました。

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'NULL' not found. Available parameters are [id, param1]
 at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96)
 at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
 at com.sun.proxy.$Proxy72.selectOne(Unknown Source)
 at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160)
 at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87)
 at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
 at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
 at com.sun.proxy.$Proxy86.selectNullError(Unknown Source)
 at jp.com.app.mapper.NullErrorMapperTest.Error_Test(NullErrorMapperTest.java:24)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'NULL' not found. Available parameters are [id, param1]
 at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
 at org.apache.ibatis.scripting.xmltags.DynamicContext$ContextAccessor.getProperty(DynamicContext.java:120)
 at org.apache.ibatis.ognl.OgnlRuntime.getProperty(OgnlRuntime.java:3356)
 at org.apache.ibatis.ognl.ASTProperty.getValueBody(ASTProperty.java:121)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
 at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:51)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:586)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:550)
 at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46)
 at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32)
 at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
 at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
 at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:39)
 at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:305)
 at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:87)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76)
 at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)
 ... 72 more

結論

<if test=""></if><when test=""></when> などの条件は 「大文字」 ではなく 「小文字」 でかきましょう!

OKパターン(nullが小文字)
<if test="id != null ">
    AND id = #{id}
</if>
NGパターン(NULLが大文字)
<if test="id != NULL ">
    AND id = #{id}
</if>

実験(興味のある人だけ参考に・・・)

users_infomaion テーブルからidが1のユーザを取得するSQLの実行を想定します。
テーブルは以下を想定します。

Create文
CREATE TABLE users_infomaion (
  id integer,
  name VARCHAR(255)
);

以下のデータを追加します。

Insert文
INSERT INTO users_infomaion VALUES(1,'Tarou');
INSERT INTO users_infomaion VALUES(2,'Jirou');
INSERT INTO users_infomaion VALUES(3,'Saburou');

SQL結果取得用のBean(Entity)は以下です。

SQL結果取得用のBean
package jp.com.app.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SampleEntity1Response {
    private Integer id;
    private String name;
}

Mapper.java は以下です。それぞれ正常終了用(selectRunning)と異常終了用(selectNullError)を作成しています。

Mapper.java
package jp.com.app.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import jp.com.app.entity.SampleEntity1Response;

@Mapper
public interface NullErrorMapper {
    SampleEntity1Response selectRunning(@Param("id")Integer id);

    SampleEntity1Response selectNullError(@Param("id")Integer id);
}
Mapper.xml
<?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="jp.com.app.mapper.NullErrorMapper">
    <!-- 正常終了版 -->
    <select id="selectRunning" resultType="jp.com.app.entity.SampleEntity1Response">
        SELECT
            id,
            name
        FROM
            users_infomaion
        <where> 
            <!-- ※ nullが小文字 -->
            <if test="id != null ">
                AND id = #{id}
            </if>
        </where>
    </select>
    <!-- 異常終了版 -->
    <select id="selectNullError" resultType="jp.com.app.entity.SampleEntity1Response">
        SELECT
            id,
            name
        FROM
            users_infomaion
        <where> 
            <!-- ※ NULLが大文字 -->
            <if test="id != NULL ">
                AND id = #{id}
            </if>
        </where>
    </select>
</mapper>

Junitで直接Mapperを呼び出して実行することとします。

Testクラス
package jp.com.app.mapper;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import jp.com.app.entity.SampleEntity1Response;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class NullErrorMapperTest {
    @Autowired
    NullErrorMapper mapper;
    @Test
    public void Runnning_Test()throws Exception{
        Integer id = 1;
        SampleEntity1Response res = mapper.selectRunning(id);
        System.out.println("**************************************************************");
        System.out.println(res);
        System.out.println("**************************************************************");
    }

    @Test
    public void Error_Test()throws Exception{
        Integer id = 1;
        SampleEntity1Response res = mapper.selectNullError(id);
        System.out.println("**************************************************************");
        System.out.println(res);
        System.out.println("**************************************************************");
    }
}

以下のようにResponseの値がコンソールに表示されたら成功です。
...省略
2022-08-30 15:06:29.502  INFO 25171 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
**************************************************************
SampleEntity1Response(id=1, name=Tarou)
**************************************************************
2022-08-30 15:06:29.714  INFO 25171 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
```...省略

以下のようなエラーが出たら失敗です。

実行結果(異常終了パターン)
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'NULL' not found. Available parameters are [id, param1]
 at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96)
 at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
 at com.sun.proxy.$Proxy72.selectOne(Unknown Source)
 at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160)
 at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87)
 at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
 at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
 at com.sun.proxy.$Proxy86.selectNullError(Unknown Source)
 at jp.com.app.mapper.NullErrorMapperTest.Error_Test(NullErrorMapperTest.java:26)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'NULL' not found. Available parameters are [id, param1]
 at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:212)
 at org.apache.ibatis.scripting.xmltags.DynamicContext$ContextAccessor.getProperty(DynamicContext.java:120)
 at org.apache.ibatis.ognl.OgnlRuntime.getProperty(OgnlRuntime.java:3356)
 at org.apache.ibatis.ognl.ASTProperty.getValueBody(ASTProperty.java:121)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
 at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:51)
 at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
 at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:586)
 at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:550)
 at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46)
 at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32)
 at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
 at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
 at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
 at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
 at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:39)
 at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:305)
 at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:87)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76)
 at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)
 ... 72 more

最後に

MybatisはResponseのBean(Entity)の変数名の型とカラムの名前が一致していないと値がとれなかったりなどがあるので名前には気をつけましょう。ちなみに、筆者は「resultMap」と「「resultType」を見間違えてはまってしまったこともあります。注意深く確認しましょう!

1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?