(Как) я могу использовать "LIKE" в SQL-запросах с помощью MyBatis безопасно и DB-agnostic?
В MyBatis вы отмечаете места, где параметры должны быть вставлены в ваш SQL следующим образом:
SELECT * FROM Person WHERE id = # {id}
Этот синтаксис активирует правильное экранирование и т.д., чтобы избежать, среди прочего, атак SQL-инъекций. Если у вас есть доверенный ввод и вы хотите пропустить экранирование, вы можете вставить параметры дословно:
SELECT * FROM {tableName} WHERE id = # {id}
Теперь я хочу сделать LIKE-поиск на небезопасном входе, поэтому я хочу сделать следующее:
SELECT * FROM Person WHERE name LIKE # {beginOfName} || '%'
К сожалению, однако, важные серверы базы данных не поддерживают синтаксис ||
для конкатенации:
MSSQL - Прерывает стандарт, используя оператор "+" вместо "||".
...
MySQL - Плохо нарушает стандарт путем переопределения || означает OR.
Итак, я мог бы сделать
SELECT * FROM Person WHERE name LIKE CONCAT (# {beginOfName}, '%')
и ограничиваться, в данном случае, MySQL, или я мог бы сделать
SELECT * FROM Person WHERE name LIKE '{beginOfName}%'
и придется самостоятельно дезинформировать ввод.
Есть ли более элегантное решение?
Ответы
Ответ 1
Обычно это делается путем добавления %
к самому параметру перед его передачей на любом языке, который вы используете вне SQL. Однако обратите внимание, что в любом случае вам может потребоваться выполнить шаг экранирования, если ваш поисковый запрос может содержать _
или %
. См. Например этот вопрос для фона.)
Чтобы исправить проблему конкатенации в целом, поместите MySQL в ANSI sql_mode, и вы получите правильную поддержку для оператора ||
, а также как правильная обработка двойных кавычек для имен схем, а не строковых литералов.
(Если вы не можете этого сделать, вам нужно будет построить функцию для построения выражения из ||
или CONCAT()
, абстрагируя разницу.)
Ответ 2
Вы можете использовать синтаксис привязки
Цитата Официальная документация
Элемент bind позволяет создать переменную из выражения OGNL и привязать его к контексту. Например:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
Ответ 3
привязка включает внутри if
<select id="select" parameterType="java.util.Map" resultType="ViajeDTO">
SELECT A.ID_VIAJE ID, A.NOMBRE, A.DESCRIPCION, A.FINICIO, A.FFIN, A.LOGO, A.URL,
A.ID_CLIENTE IDCLIENTE, B.NOMBRE CLIENTE
FROM VIAJE A
INNER JOIN CLIENTE B ON (A.ID_CLIENTE = B.ID_CLIENTE)
WHERE A.ESTATUS = 1
<if test="P_NOMBRE != null">
<bind name="pattern" value="'%' + P_NOMBRE + '%'" />
AND A.NOMBRE LIKE #{pattern}
</if>
</select>
Ответ 4
Мы можем использовать Привязать. Элемент bind позволяет вам создать переменную из выражения и привязать ее к контексту. Например:
<select id="select" parameterType="java.util.Map" resultType="ViajeDTO">
<bind name="pattern" value="'%' + P_NOMBRE + '%'" />
SELECT A.ID_VIAJE ID, A.NOMBRE, A.DESCRIPCION, A.FINICIO, A.FFIN, A.LOGO, A.URL,
A.ID_CLIENTE IDCLIENTE, B.NOMBRE CLIENTE
FROM VIAJE A
INNER JOIN CLIENTE B ON (A.ID_CLIENTE = B.ID_CLIENTE)
WHERE A.ESTATUS = 1
<if test="P_NOMBRE != null">
AND A.NOMBRE LIKE #{pattern}
</if>
</select>
Принимая во внимание, что параметр для поиска - P_NAME.
Ответ 5
Оператор ||
работал у меня в IBatis, но не в Mybatis.
В MyBatis мне пришлось использовать оператор +
.
SELECT *
FROM Employee
WHERE
name like '%' + #{searchName,jdbcType=NVARCHAR} + '%'