MyBatisのArrayTypeHandler使用時の注意点

MyBatisには、org.apache.ibatis.type.ArrayTypeHandlerがあって、java.sql.Arrayとのマッピングを行ってくれますが、パラメータ設定時と、結果取得時でマッピングが異なるので注意が必要です。

実際のコードを見たほうがわかりやすいので、現時点のコードを引用します。

public class ArrayTypeHandler extends BaseTypeHandler<Object> {

  public ArrayTypeHandler() {
    super();
  }

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
    ps.setArray(i, (Array) parameter);
  }

  @Override
  public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
    Array array = rs.getArray(columnName);
    return array == null ? null : array.getArray();
  }

  @Override
  public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    Array array = rs.getArray(columnIndex);
    return array == null ? null : array.getArray();
  }

  @Override
  public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    Array array = cs.getArray(columnIndex);
    return array == null ? null : array.getArray();
  }
}

パラメータ設定時(setNonNullParameterメソッド)では、java.sql.Arrayを パラメータとして求めますが、結果取得時(getNullableResultメソッド)だと、java.sql.ArrayからgetArrayしたもの(たとえばPostgreSQLのintの配列(int[])だと、Javaのint[])が返却されます。 そのため、同じEntityを使ってInsertとSelectを行うということができません。

java.sql.Arrayを生成する際に、配列のタイプを文字列で指定する必要があり、汎用的なTypeHandlerを作るのが難しいのでこのようになってしまっているのではと思いますが、そのあたりの理由を知っていないと、嵌りそうですね。

同じEntityを使いたい場合には、ArrayTypeHandlerを使わずに、そのARRAYの型に応じたTypeHandlerを独自に作ることになりそうです。TypeHandler自体はとてもシンプルなので、実装も簡単です。 参考までに、List<Integer>と、PostgreSQLのint[]をマッピングするTypeHandlerの実装を以前作ったので、リンクしておきます。