¿Cómo se enfrenta MyBatis a un conjunto de resultados vacío?

Recently I was using Mybatis3 and found that when your SQL statement gets an empty result set from the database, Mybatis creates a new List and returns it to your program.

Given some code, like:

List<User> resultList = (List<User>)sqlSession.select("statementId");

<select id="statementId" resultType="User">
   select * from user where id > 100
</select>

assume that the above SQL return no rows (i.e. there is no id greater than 100).

La variable resultList will then be an empty Listpero yo quiero que sea null instead. How can I do that?

preguntado el 28 de agosto de 12 a las 10:08

2 Respuestas

It's better to have an empty collection instead of null as a result of your query. When working with a collection you usually loop through each item and do something with it, something like this:

List<User> resultList = (List<User>) sqlSession.select("statementId");
for (User u : resultList) { 
   //... 
}

which doesn't do anything if the list is empty.

But if you return null, you have to guard your code against NullPointerExceptions and write code like this instead:

List<User> resultList = (List<User>) sqlSession.select("statementId");
if (resultList != null) {
  for (User u : resultList) { 
     //... 
  }
}

The first approach is usually better and MyBatis does it like that, but you could force it to return null, if that is really what you want.

For that you could write a MyBatis plugin and intercept calls to any query and then return null if the query result is empty.

Aquí hay un código:

In your configuration add:

<plugins>
   <plugin interceptor="pack.test.MyInterceptor" />
</plugins>

El código del interceptor:

package pack.test;

import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) })
public class MyInterceptor implements Interceptor {
    public Object intercept(Invocation invocation) throws Throwable {
        Object result = invocation.proceed();
        List<?> list = (List<?>) result;
        return (list.size() == 0 ? null : result);
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
    }
}

You could then further limit the scope of the interceptor if you intercept calls to ResultSetHandler en lugar de Executor.

Respondido el 23 de Septiembre de 12 a las 11:09

It is always better to use empty list instead of null for the following reasons.

Careless use of null can cause a staggering variety of bugs.

Additionally, null is unpleasantly ambiguous. It's rarely obvious what a null return value is supposed to mean -- for example, Map.get(key) can return null either because the value in the map is null, or the value is not in the map. Null can mean failure, can mean success, can mean almost anything. Using something other than null makes your meaning clear.

good discussion about null usage

contestado el 23 de mayo de 17 a las 13:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.