💭

MyBatis × Oracleでハマる “Invalid column type: 1111” エラーの原因と対策

に公開

はじめに

Spring Boot × MyBatis × Oracle の構成で開発していると、INSERTやUPDATE時に突然こんなエラーが出ることがあります。

java.sql.SQLException: Invalid column type: 1111

アプリケーションログを見ると、MyBatisSystemException が発生し、SQL実行部分で止まっています。
本記事では、このエラーの正体と、どう直せば良いかを具体的なコード例で解説します。


エラーの原因

Oracleで Invalid column type: 1111 が出るのは、JDBCの Types.OTHER (1111) が setNull() に渡されるためです。

MyBatisは、パラメータが null の場合、デフォルトで jdbcType=OTHER として扱います。
しかしOracleドライバは Types.OTHER をサポートしていないため、Invalid column type: 1111 という例外を投げます。


💥 エラーが起きる従来のコード

たとえば、次のようなマッパーを考えてみましょう。

<!-- NG例: jdbcType未指定 -->
<insert id="insertUser" parameterType="User">
  INSERT INTO USERS (ID, NAME, AGE, NOTE)
  VALUES (#{id}, #{name}, #{age}, #{note})
</insert>

Java側で以下のように null を渡すと……

User user = new User();
user.setId(1);
user.setName("Suzuki");
user.setAge(null); // ← nullを設定
user.setNote(null); // ← nullを設定
userMapper.insertUser(user);

これがOracleでは Invalid column type: 1111 で落ちます。
MyBatisが PreparedStatement.setNull(parameterIndex, Types.OTHER) を呼び出すためです。


✅修正版①: jdbcType を明示的に指定する

最も確実な方法は、MyBatisマッパーで jdbcType を明示的に設定することです。

<!-- OK例: jdbcTypeを明示 -->
<insert id="insertUser" parameterType="User">
  INSERT INTO USERS (ID, NAME, AGE, NOTE)
  VALUES (
    #{id,jdbcType=NUMBER},
    #{name,jdbcType=VARCHAR},
    #{age,jdbcType=NUMBER},
    #{note,jdbcType=VARCHAR}
  )
</insert>

これでMyBatisは、null の場合でも適切な型 (setNull(index, java.sql.Types.NUMBER) など) でOracleに値を送ります。
結果、Invalid column type: 1111 は発生しません。


✅修正版②: MyBatisの設定でデフォルトを変更する

もし毎回 jdbcType を書くのが面倒な場合は、mybatis-config.xml に次の設定を追加します。

<settings>
  <setting name="jdbcTypeForNull" value="NULL"/>
</settings>

これにより、MyBatisが内部的に Types.OTHER ではなく Types.NULL を使用します。
シンプルな対応ですが、プロジェクト全体に影響するため慎重に導入してください。


✅修正版③: 動的SQLで null カラムをスキップ

null をDBに入れたくない場合は、動的SQLを使って該当列をスキップするのも有効です。

<insert id="insertUser" parameterType="User">
  INSERT INTO USERS
  <trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="id != null">ID,</if>
    <if test="name != null">NAME,</if>
    <if test="age != null">AGE,</if>
    <if test="note != null">NOTE,</if>
  </trim>
  <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
    <if test="id != null">#{id},</if>
    <if test="name != null">#{name},</if>
    <if test="age != null">#{age},</if>
    <if test="note != null">#{note},</if>
  </trim>
</insert>

これにより、null の項目をSQLに含めず安全にINSERTできます。


🧠 まとめ

  • MyBatisはnullを扱う際、デフォルトでTypes.OTHERを使う
  • Oracleはこれを受け付けず、Invalid column type: 1111が発生する
    • 対策は以下のいずれか:
      1. jdbcType を明示する(推奨)
      2. mybatis-config.xml で jdbcTypeForNull=NULL を設定
      3. 動的SQLで null カラムをスキップする

💬 おわりに

本エラーは一見「Oracle側の問題」に見えますが、実際にはMyBatisのJDBC型推定の仕様が原因です。Oracle特有の制約により発生しやすいので、マッパーに jdbcType を書く習慣を付けておくと安全です。

Discussion