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

# 事象 : You have an error in your SQL syntax

<details><summary>詳細</summary><div>

- 環境
    - 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"

```bash
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
#...省略...
```
</div></details>

## 原因 : CDATAセクションはプレーンなテキストとして評価されるため
マッピングファイルに不等号を使うSQLを追加するのでCDATAセクションを使った。

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

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

> **改善策②**
> 下の例のようにSELECT句全体を囲んでも良かった。
> こっちのほうが可読性は高い。（気がする。）
> [MyBatisのSQLで不等号の比較演算子を使う - Qiita](https://qiita.com/riekure/items/4a114590c6c48801e590)

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

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

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


### 対応 : CDATAセクションの範囲を狭める
```xml:マッピングファイル
    <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を追加した
1. Tomcatを起動したら警告が大量に出てタイムアウトを起こした

<details><summary>詳細</summary><div>

- 環境
    - 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"

```bash:コンソールのエラーに改行を入れたやつ
警告: 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:マッピングファイル
<?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">
```

```java:Mapperインターフェース
import com.example.domain.NewBean;

public interface IMyMapper {
    List<NewBean> getNewBeans();
}
```
</div></details>

## 原因 : エイリアスを指定していないのにマッピングファイルにクラス名を指定するから
```bash
# 設定ファイルにはTypeAiliasがない！
$ grep -i alias mybatis-config.xml
$
```

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

### 対応 : マッピングファイルにパッケージ名まで指定する
大人の事情でmybatis-config.xmlは修正できないのでマピングファイルを修正する。

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




























































































# 事象 : Result Maps collection does not contain value for
1. MyBatisで既存のMapperインターフェースとマッピングファイル(xml)にSQLを追加した
1. アプリの追加したとことは関係ないとこに接続したらエラー

<details><summary>環境とコンソールのエラー</summary><div>

- 環境
    - 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"


```bash
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
```
</div></details>


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

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

```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="com.example.IMyMapper">
    <select id="getNewBeans" resultMap="NewBean">
        SELECT...
```

```java:Mapperインターフェース
public interface IMyMapper {
    List<NewBean> getNewBeans();
}
```

### 対応 : selectタグのresultMap属性をresultType属性に変更する
明示的なマッピング(resultMap属性)をやめて暗黙的なマッピング(resultType属性)にかえたら属性を修正しましょう。

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






























































# 事象 : It's likely that neither a Result Type nor a Result Map was specified.
1. MyBatisで既存のMapperインターフェースとマッピングファイル(xml)にSQLを追加した
1. アプリの追加したとこに接続したらエラー

<details><summary>環境とコンソールのエラー</summary><div>


- 環境
    - 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"

```bash
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
```
</div></details>


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

```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="com.example.IMyMapper">
    <select id="getNewBeans">
```

```java:Mapperインターフェース
public interface IMyMapper {
    List<NewBean> getNewBeans();
}
```

### 対応 : resultMapかresultTypeを定義する

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

上記表の出典 : [MyBatis &#x2013; MyBatis 3 | Mapper XML ファイル](https://mybatis.org/mybatis-3/ja/sqlmap-xml.html)

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