Динамический блок where в MyBatis
Динамический sql позволяет формировать запрос в зависимости от значения входных параметров. Для этого mybatis содержит условные конструкции и ряд вспомогательных конструкций для упрощения процесса программирования динамических запросов. Одной из таких вспомогательных конструкция является элемент <where>. Для понимания зачем он нужен рассмотрим пример:
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES WHERE <if test=" tutorId != null "> TUTOR_ID= #{tutorId} </if> <if test="courseName != null"> AND name like #{courseName} </if> <if test="startDate != null"> AND start_date >= #{startDate} </if> <if test="endDate != null"> AND end_date <= #{endDate} </if> </select>
Этот код будет работать равно до того момента пока hashmap['tutorId'] не равен null. Если возникнет ситуация когда hashmap['tutorId'] окажется равным null то будет сгенерирован некорректный sql-код вне зависимости от значения остальных параметров.
Например итоговый sql - может стать таким:
Пример 1.
SELECT * FROM COURSES WHERE AND name LIKE 'Java course'
тут очевидно будет лишним оператор AND
Запрос может получится таким:
Пример 2.
SELECT * FROM COURSES WHERE
если все входные параметры будут иметь значение null.
из данной ситуации есть 3 выхода:
1. Для первого примера: проверять были ли проинициализированы предыдущие параметры. Естественно это приведет не только к увеличению количества вложенных условных блоков, но и проблемы в отладке при внесении изменений в динамические sql. Для второго примера можно проверять то, что хотя бы один из входных параметров удовлетворяет описанным в блоке where условиям, т.е. фактически надо продублировать все проверки блока where.
2. Использовать фиктивное условие "1=1", например так:
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES WHERE 1=1 <if test=" tutorId != null "> AND TUTOR_ID= #{tutorId} </if> <if test="courseName != null"> AND name like #{courseName} </if> <if test="startDate != null"> AND start_date >= #{startDate} </if> <if test="endDate != null"> AND end_date <= #{endDate} </if> </select>
3. Использовать элемент <where>. В случае если в, приведенном в начале поста, примере все входные параметры окажутся равны null то ключевое слово where просто не будет добавлено в sql-выражение. В случае если сразу после where будет стоять AND или OR, то на стадии формирования sql-запроса mybatis удалит эти лишние логические операторы.
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES <where> <if test=" tutorId != null "> TUTOR_ID= #{tutorId} </if> <if test="courseName != null"> AND name like #{courseName} </if> <if test="startDate != null"> AND start_date >= #{startDate} </if> <if test="endDate != null"> AND end_date <= #{endDate} </if> </where> </select>