Я изучаю, как использовать MyBatis. Честно говоря, мне очень нравятся эти рамки. Он прост в использовании, и я доволен его, потому что я могу использовать свои команды sql с ним :) Я использую MyBatis 3.4.2 и базу данных PostgreSQL.отображение входных и выходных параметров с помощью MyBatis
Например, мне нравится, как легко выполнить запрос перед вставкой с аннотацией @SelectKey
. И отображение данных работает как шарм, если я добавлю некоторую аннотацию перед интерфейсом, примерно так: @Results({ @Result(property = "javaField", column = "database_field", javaType = TypeHandler.class)
.
Что мне не нравится (и я надеюсь, что вы можете поместить меня в правильном направлении), являются следующие:
(Выпуск 1) У меня есть вопросы, которые позволяют мне используйте нулевое и нормальное значение без каких-либо дополнительных «if» java-операторов, чтобы проверить, содержит ли переменная значение null или нет. Они выглядят следующим образом:
SELECT * FROM table
WHERE key_name = ? AND ((? IS NULL AND user_id IS NULL) OR User_id = ?)
С JDBC мне нужно на следующее:
stmt = connection.prepareStatement(query);
stmt.setString(1, "key");
stmt.setString(2, userId);
stmt.setString(3, userId);
Как вы можете видеть, что нужно пройти два раза USERID потому, что это так, как работает JDBC. Честно говоря, я ожидал, что следующий код ниже будет работать с MyBatis, но, к сожалению, он не работает. Необходимо определить третий параметр.
Интересно, можно ли добавить эту функцию в MyBatis. Это должно быть хорошо, если MyBatis может связать USERID дважды автоматически, что-то вроде этого:
@Select("SELECT * FROM table key_name = #{key} and ((#{userId} is null and user_id is null) OR user_id = #{userId})
SomeClass findByKeyAndUserId(String key, Long userId);
Что обходной путь на самом деле я сделал следующий. Я ненавижу это, потому что это сложно и дополнительные Java «если» заявление необходимо:
@Select("SELECT * FROM table WHERE key_name = #{key} AND COALESCE(user_id, -1) = #{userId}")
SomeClass findByKeyAndUserId(String key, Long userId);
userId = (userId == null) ? -1 : userId;
SomeClass abc = mapper.findByKeyAndUserId(key, userId);
Я не знаю, что это лучшая практика, чтобы справиться с этой ситуацией с MyBatis. Пожалуйста, направляйте меня.
(Выпуск 2) Картирование в случае @Select
. Есть ли способ избежать повторного кода при отображении результата запросов с тем же типом результата?
первый запрос:
@Select("SELECT * FROM table WHERE ...")
@Results({
@Result(property = "key", column = "key_name", javaType = String.class),
@Result(property = "value", column = "key_value", javaType = String.class),
@Result(property = "userId", column = "user_id", javaType = Long.class),
@Result(property = "interval", column = "interval", javaType = Long.class),
@Result(property = "description", column = "description", javaType = String.class),
@Result(property = "status", column = "status", typeHandler = StatusTypeHandler.class)
})
SomeClass findByKeyAndUserId(@Param("key") String key, @Param("userId") Long userId);
второй запрос:
@Select("SELECT * FROM table WHERE <different conditions then before>")
@Results({
<I need to add here the exact same code then before in query 1>
})
SomeClass findByKeyAndUserId(@Param("key") String key, @Param("userId") Long userId);
Можно ли использовать как-то код, связанные отображение? Мне нужно добавить сопоставление, потому что я использую специальный обработчик типа для поля состояния. Я использую конфигурацию на основе аннотации.
(Выпуск 3)@Param
аннотацию я ничего не мог видеть в документации о @Param
аннотаций. Трудно было понять, почему мои параметры java не были ограничены должным образом.Наконец, я понял, что в моем коде отсутствовала аннотация @Param
. Почему это не упоминается в официальной документации? Я сделал что-то не так, и @Param
не нужно использовать?
Этот код работает отлично:
SomeClass findByKeyAndUserId(@Param("key") String key, @Param("userId") Long userId);
Это не работает:
SomeClass findByKeyAndUserId(String key, Long userId);
ОБНОВЛЕНИЕ ДЛЯ (Выпуск 1)
Мой первый идея была аналогична с этим @blackwizard menti oned: «Mybatis связывает параметры по имени, затем один раз, дважды, N раз, как может быть время, на которое он ссылается, он работает».
Но это на самом деле не работает должным образом. Он работает, если userId не равен null. Если это null, я получаю прекрасное исключение, которое возвращается из базы данных. Я предполагаю, что MyBatis связывает нулевое значение неправильно. Возможно, это ошибка. Я не знаю :(
Exception:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $2
### The error may exist in com/.../dao/TableDao.java (best guess)
### The error may involve ....dao.Table.findByKeyAndUserId-Inline
### The error occurred while setting parameters
### SQL: SELECT * FROM table WHERE key_name = ? AND (? IS NULL AND user_id IS NULL) OR user_id = ? AND status = 1
### Cause: org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $2
Наконец я нашел три различных решения
(Выпуск 1: раствор 1).
Я последовал за то, что @blackwizard, и я смог переместить условие userId = (userId == null) ? -1 : userId
с уровня Java на уровень MyBatis. И это неплохо! Правильный синтаксис: <if test='userId==null'><bind name='userId' value='-1'/></if>
.
(Выпуск 1: Раствор 2) Причина, почему я возвращаюсь could not determine data type of parameter $2
ошибку от Postgres, потому что в случае, если на нулевое значение драйвер JDBC не может определить тип параметра. Итак, давайте определим его вручную.
@Select("SELECT * FROM table "
+ "WHERE key_name = #{key} AND ((#{userId}::BIGINT IS NULL AND user_id IS NULL) OR user_id = #{userId})")
})
SomeClass findByKeyAndUserId(@Param("key") String key, @Param("userId") Long userId);
(Выпуск 1: Раствор 3) 2-е решение зависит от PorstgreSQL. Следующее решение полностью независимо от базы данных. Спасибо за @blackwizard за хороший комментарий.
@Select("SELECT * FROM table "
+ "WHERE key_name = #{key} AND ((#{userId, jdbcType=BIGINT} IS NULL AND user_id IS NULL) OR user_id = #{userId})")
})
SomeClass findByKeyAndUserId(@Param("key") String key, @Param("userId") Long userId);
Лично я предпочитаю решение 3. Он содержит менее дополнительный код.
Большое спасибо за ваш ответ. Я обновил свое оригинальное сообщение для (выпуск 1).Не могли бы вы проверить его? Завтра буду проверять ваши два ответа. – zappee
3-я проблема теперь понятна. Большое спасибо! Так вот почему я иногда вижу в журнале исключений, что привязка paramX неверна;) – zappee
Я обновил сообщение. Первая проблема полностью решена. Спасибо за вашу помощь! – zappee