12
7

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 3 years have passed since last update.

MyBatisでエラーになって困った事例集

Last updated at Posted at 2021-01-26

事象 : You have an error in your SQL syntax

詳細
  • 環境
    • Windows10 Pro バージョン1909
    • mybatis-3.3.0.jar
    • mybatis-spring-1.2.2.jar
    • Eclipse IDE for Enterprise Java Developers Version: 2020-09 (4.17.0)
    • java version "1.8.0_251"
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
 You have an error in your SQL syntax;
  check the manual that corresponds to your MySQL server version for the right syntax to use near '<!-- 説明用のコメント -->
            GROUP BY DATE_FORMAT(' at line 5
#...省略...

原因 : CDATAセクションはプレーンなテキストとして評価されるため

マッピングファイルに不等号を使うSQLを追加するのでCDATAセクションを使った。

マッピングファイルはXML形式のため、SQL内に「<」や「>」を直接記述することができません。
これは、エンティティ参照文字(<や>など)で代替することもできますが、可読性はあまりよくありません。
数値や日付の大小比較で「<」や「>」を記述したい場合は、SQLの可読性を考慮してCDATAセクションをうまく活用しましょう。
CDATAセクションはプレーンなテキストとして評価されるため、「<」や「>」を直接記述することができます。
Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発(株式会社NTTデータ)|翔泳社の本

どんぐらい囲もうかと思った時に以下サイトを見て、確かにSQL文全部囲んだら見やすい気がした。

改善策②
下の例のようにSELECT句全体を囲んでも良かった。
こっちのほうが可読性は高い。(気がする。)
MyBatisのSQLで不等号の比較演算子を使う - Qiita

あっ、説明用のコメント書こっと・・・そして、実行したらエラーーー

マッピングファイル
    <select id="getHoge" resultType="_int">
    <![CDATA[
        ...省略...
        <!-- 説明用のコメント -->
        GROUP BY DATE_FORMAT(col_name, '%Y%m')
        HAVING COUNT(*) >= 12
    ]]>
    </select>

参考にしている本に書いてあるし・・・XMLのコメント書いてもねぇ・・・

対応 : CDATAセクションの範囲を狭める

マッピングファイル
    <select id="getHoge" resultType="_int">
        ...省略...
        <!-- 説明用のコメント -->
        GROUP BY DATE_FORMAT(col_name, '%Y%m')
        HAVING COUNT(*) <![CDATA[>=]]> 12
    </select>

事象 : Could not resolve type alias

  1. MyBatisで既存のMapperインターフェースとマッピングファイル(xml)にSQLを追加した
  2. Tomcatを起動したら警告が大量に出てタイムアウトを起こした
詳細
  • 環境
    • Windows10 Pro バージョン1909
    • mybatis-3.3.0.jar
    • mybatis-spring-1.2.2.jar
    • Eclipse IDE for Enterprise Java Developers Version: 2020-09 (4.17.0)
    • java version "1.8.0_251"
コンソールのエラーに改行を入れたやつ
警告: Bean creation exception on non-lazy FactoryBean type check:
 org.springframework.beans.factory.UnsatisfiedDependencyException:
  Error creating bean with name 'hogeMapper' defined in URL [jar:file:/C:/apps/pleiades/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/my-api/WEB-INF/lib/project-2.20.0-SNAPSHOT.jar!/com/example/HogeMapper.class]:
   Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException:
     Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring/application-context.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException:
       Failed to parse mapping resource: 'URL [jar:file:/C:/apps/pleiades/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/my-api/WEB-INF/lib/project-2.20.0-SNAPSHOT.jar!/mybatis/mapper/MyMapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML.
        Cause: org.apache.ibatis.builder.BuilderException: Error resolving class.
          Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'NewBean'.
            Cause: java.lang.ClassNotFoundException: Cannot find class: NewBean
マッピングファイル
<?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="com.example.persistence.IMyMapper">
    <select id="getNewBeans" resultType="NewBean">
Mapperインターフェース
import com.example.domain.NewBean;

public interface IMyMapper {
    List<NewBean> getNewBeans();
}

原因 : エイリアスを指定していないのにマッピングファイルにクラス名を指定するから

# 設定ファイルにはTypeAiliasがない!
$ grep -i alias mybatis-config.xml
$

TypeAlias
TypeAliasとは、マッピングファイルで指定するJavaクラスに対して、エイリアス(短縮名)を割り当てる機能です。
TypeAliasを使用しない場合、Javaクラスを完全修飾クラス名(FQCN)で指定する必要があります。
TypeAliasを使用すると、記述効率の向上、記述ミスの削減、マッピングファイルの可読性向上などの効果が期待できます。
Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発(株式会社NTTデータ)|翔泳社の本

対応 : マッピングファイルにパッケージ名まで指定する

大人の事情でmybatis-config.xmlは修正できないのでマピングファイルを修正する。

マッピングファイル
    <select id="getNewBeans" resultType="com.example.domain.NewBean">

事象 : Result Maps collection does not contain value for

  1. MyBatisで既存のMapperインターフェースとマッピングファイル(xml)にSQLを追加した
  2. アプリの追加したとことは関係ないとこに接続したらエラー
環境とコンソールのエラー
  • 環境
    • Windows10 Pro バージョン1909
    • mybatis-3.3.0.jar
    • mybatis-spring-1.2.2.jar
    • Eclipse IDE for Enterprise Java Developers Version: 2020-09 (4.17.0)
    • java version "1.8.0_251"
org.apache.ibatis.builder.IncompleteElementException: Could not find result map com.example.IMyMapper.NewBean
    at org.apache.ibatis.builder.MapperBuilderAssistant.setStatementResultMap(MapperBuilderAssistant.java:358) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:296) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:109) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:718) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:688) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:683) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:183) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:44) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:59) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52) ~[mybatis-3.3.0.jar:3.3.0]
# ...省略...
Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.example.IMyMapper.NewBean
    at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:818) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.Configuration.getResultMap(Configuration.java:570) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.builder.MapperBuilderAssistant.setStatementResultMap(MapperBuilderAssistant.java:356) ~[mybatis-3.3.0.jar:3.3.0]
    ... 86 common frames omitted

原因 : resultMapを指定したのに定義がないから

<resultMap id="NewBean"...を定義したが、本を読んで・・・resultMapの定義いらないじゃん!と思って定義だけ消した・・・selectタグの属性はいじらずに・・・。

RsultSetとJavaBeanの暗黙的なマッピング
...省略...
SQL実行結果と戻り値となるオブジェクト間のマッピングはMyBatisにより自動的に行われます。
具体的にはSQL実行結果であるResultSetに含まれるカラム名とメソッドの戻り値のJavaBean型のプロパティ名が一致した場合、そのプロパティに該当のカラム値を格納します。
Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発(株式会社NTTデータ)|翔泳社の本

マッピングファイル
<?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="com.example.IMyMapper">
    <select id="getNewBeans" resultMap="NewBean">
        SELECT...
Mapperインターフェース
public interface IMyMapper {
    List<NewBean> getNewBeans();
}

対応 : selectタグのresultMap属性をresultType属性に変更する

明示的なマッピング(resultMap属性)をやめて暗黙的なマッピング(resultType属性)にかえたら属性を修正しましょう。

マッピングファイル
    <select id="getNewBeans" resultType="NewBean">

事象 : It's likely that neither a Result Type nor a Result Map was specified.

  1. MyBatisで既存のMapperインターフェースとマッピングファイル(xml)にSQLを追加した
  2. アプリの追加したとこに接続したらエラー
環境とコンソールのエラー
  • 環境
    • Windows10 Pro バージョン1909
    • mybatis-3.3.0.jar
    • mybatis-spring-1.2.2.jar
    • Eclipse IDE for Enterprise Java Developers Version: 2020-09 (4.17.0)
    • java version "1.8.0_251"
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'com.example.IMyMapper.getNewBeans'.  It's likely that neither a Result Type nor a Result Map was specified.
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75) ~[mybatis-spring-1.2.2.jar:1.2.2]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371) ~[mybatis-spring-1.2.2.jar:1.2.2]
# ...省略...
Caused by: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'com.example.IMyMapper.getNewBeans'.  It's likely that neither a Result Type nor a Result Map was specified.
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.validateResultMapsCount(DefaultResultSetHandler.java:234) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:157) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:63) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:78) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:62) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:303) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:154) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:102) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:82) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_251]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_251]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
    ... 82 common frames omitted

原因 : 返却値の型の設定がないから

マッピングファイル
<?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="com.example.IMyMapper">
    <select id="getNewBeans">
Mapperインターフェース
public interface IMyMapper {
    List<NewBean> getNewBeans();
}

対応 : resultMapかresultTypeを定義する

属性 説明
resultType このステートメントから返されるオブジェクトの型。完全修飾クラス名またはエイリアス。ステートメントがコレクションを返す場合は、コレクションの型ではなくコレクションに含まれるオブジェクトの型を指定する必要があります。
resultTyperesultMapは、どちらか一方のみ指定可能です。
resultMap 別の場所で定義されているresultMapを参照します。Result Map は MyBatis の中でも最も強力な機能で、深く理解すれば複雑なマッピングが必要となる様々なケースに対応することができます。
resultTyperesultMapは、どちらか一方のみ指定可能です。

上記表の出典 : MyBatis – MyBatis 3 | Mapper XML ファイル

マッピングファイル
    <!--今回は暗黙的なマッピングができるのでresultType属性を指定する-->
    <select id="getNewBeans" resultType="NewBean">
12
7
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
12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?