How to pass an Integer Array to IN clause in MyBatis

There is a query in my Mybatis containing an IN clause which is basically a set of Id's ( Integers)

I am now stuck on how can I pass an Integer array to this IN clause so that it pulls up the proper records.Tried by passing a String containing the ID's to the IN clause , but this did not work as expected.

Code Sample below

Mybatis Method using Annotations

@Select(SEL_QUERY)
    @Results(value = {@Result(property="id",column="ID")})
    List<Integer> getIds(@Param("usrIds") Integer[] usrIds);

Query

select distinct ID from table a where a.id in ( #{usrIds} )

Method Call

Integer[] arr = new Integer[2];
arr[0] = 1;
arr[1] = 2;

mapper.getIds(arr)

This is not working , Mybatis throws an error when I call the mapper method

Any suggestions please


Solution 1:

The myBatis User Guide on Dynamic SQL has an example on how to use a foreach loop to build the query string, which works for lists and arrays.

Prior to release 3.2 you had to use xml configuration to use dynamic sql, with newer versions it should also be possible to use dynamic sql in annotations.

<select id="selectPostIn" resultType="domain.blog.Post">
    SELECT *
    FROM POST P
    WHERE ID in
    <foreach item="item" index="index" collection="list"
             open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

Solution 2:

YES, you can do that using annotations.

If you're using postgresql, you can do like in this post.

If you're using MySQL try this changes in your code sample:

Mybatis Method using Annotations

@Select(SEL_QUERY)
    @Results(value = {@Result(property="id",column="ID")})
    List<Integer> getIds(@Param("usrIds") String usrIds);

Query (using MySQL)

select distinct ID from table a where FIND_IN_SET( a.id, #{usrIds}) <> 0

Method call

Integer[] arr = new Integer[2];
arr[0] = 1;
arr[1] = 2;

String usrIds= "";
for (int id : ids) {
    usrIds += id + ",";
}

mapper.getIds(usrIds) 

Solution 3:

You can create a new type handler and use it only for your parameter. The query would change to:

SELECT ... WHERE FIND_IN_SET(id, #{usrIds, typeHandler=my.pkg.ListTypeHandler}) <> 0

And the type handler:

import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.ObjectTypeHandler;

import com.google.common.base.Joiner;

public class ListTypeHandler extends ObjectTypeHandler {
    @Override
    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setObject(i, Joiner.on(",").join((Iterable<?>) parameter), JdbcType.OTHER.TYPE_CODE);
    }
}