MyBatis 3 - получить строку SQL от mapper

Я хочу использовать MyBatis3 только для создания строки SQL (используя сопоставление xml), но получение SQL я недопустимо.

Пример: я получаю строку sql:

SELECT * FROM USER WHERE NAME = john

В этом sql нет ' char, окружающего строковое значение john

в mybatis.xml:

...
    <mappers>
        <mapper resource="sql1.xml"/>
    </mappers>
...

sql1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

   <mapper namespace="sql1">
       <select id="select1" parameterType="map" resultType="String" >
           SELECT * FROM USERS
           WHERE 
           name LIKE ${name} AND num = ${number}
       </select>
   </mapper>

в MyBatisSql.java:

SqlSessionFactory sessionFactory = ConnectionFactory.getSqlSessionFactory();
Configuration configuration = sessionFactory.getConfiguration();

Map pars = new HashMap<String, Object>();
pars.put("name", "john");    
pars.put("number", 1345);

MappedStatement ms = configuration.getMappedStatement("sql1.select1);   
BoundSql boundSql = ms.getBoundSql(params);
String sql = boundSql.getSql();
System.out.println(sql);

результат

SELECT * FROM USERS
WHERE 
name LIKE john AND num = 12345

в этом SQL, строка john, не заключена в ' char поэтому он не является допустимым SQL (моя цель - создать только допустимую строку SQL, используя myBatis). Я бы хотел:

SELECT * FROM USERS
WHERE 
name LIKE 'john' AND num = 12345

спасибо

Ответ 1

Вы должны использовать # {name} вместо ${name}.

В приведенном ниже примере будет создан действительный SQL

<mapper namespace="sql1">
    <select id="select1" parameterType="map" resultType="String" >
        SELECT * FROM USERS
        WHERE 
        name LIKE #{name} AND num = #{number}
    </select>
</mapper>

MyBatis напрямую копирует и вставляет строковый параметр, если вы используете $character. С другой стороны, он использует привязку параметров, если вы используете символ #.

Затем вы должны выполнить свой sql, используя selectMap, selectList или selectOne,

List<String> resultSet = sessionFactory.openSession().selectList("sql1.select1", pars);

Этот вызов автоматически привяжет параметры к оператору и выполнит его.

Внимание:

<select id="select1" parameterType="map" resultType="String" >
    SELECT * FROM USERS
        WHERE 
        name LIKE #{name} AND num = #{number}
</select>

может не выполняться, так как MyBatis не может сопоставить несколько столбцов (SELECT *) с одной строкой ( resultType = "String" ) показаны две возможные поправки к запросу ниже:

<!--Solution One-->
<select id="select1" parameterType="map" resultType="String" >
    SELECT name FROM USERS
        WHERE 
        name LIKE #{name} AND num = #{number}
</select>

<!--Solution Two-->
<select id="select1" parameterType="map" resultType="java.util.LinkedHashMap" >
    SELECT * FROM USERS
        WHERE 
        name LIKE #{name} AND num = #{number}
</select>

Для решения два вы должны выполнить mybatis-запрос, используя код java ниже:

List<Map<?, ?>> resultSet = sessionFactory.openSession().selectList("sql1.select1", pars);

Подробности о том, почему getBoundSql возвращает запрос с?:

Связывание параметров выполняется на уровне драйвера, поэтому вы не получите строку sql, подобную этой

SELECT * FROM USERS
WHERE 
name LIKE 'john' AND num = 12345

Вместо этого вы получите шаблон запроса sql, который готов к привязке параметров,

SELECT * FROM USERS
    WHERE 
    name LIKE ? AND num = ?

Добавление параметров в строку sql позволяет sql injection. Безопасный способ - использовать метод привязки параметров, предоставляемый с помощью SQL Driver, и MyBatis всегда использует привязку параметров.

Предположим, что вы вручную создали свою команду sql в виде строки и предположите, что я пользователь malicius пытается получить доступ к вашим данным. Я могу написать

john' or ''='

Итак, это создаст команду sql ниже:

SELECT * FROM USERS
WHERE 
name LIKE 'john' or ''='' AND num = 12345

Дополнительные преимущества привязки параметров

Вторым преимуществом привязки параметров является то, что он позволяет создавать подготовленные операторы. Предположим, что вам нужно выполнить один и тот же sql 1000 раз с разными параметрами.

Если вы создаете строки sql с привязанными параметрами,

SELECT * FROM USERS WHERE name LIKE 'john' AND num = 12345;
SELECT * FROM USERS WHERE name LIKE 'foo' AND num = 67890;
Сервер базы данных

должен будет каждый раз анализировать каждую команду sql, а затем выполнять их.

С параметризованными sql-запросами

SELECT * FROM USERS WHERE name LIKE ? AND num = ?

SQL-драйвер кэширует запрос, поэтому синтаксический анализ выполняется только один раз, а затем он связывает разные параметры с той же самой командой SQL.

Обновление: использование BoundSql вне MyBatis

Вы все равно можете использовать параметризованный sql (boundSql) с другой библиотекой или Java java.sql.Connection. Ниже приведен пример:

Connection myConnection;
PreparedStatement preparedStatement = myConnection.prepareStatement(boundSql);
preparedStatement.setString(1, "john"); //First parameter starts with 1 not 0!
preparedStatement.setInt(2, 12345);
ResultSet results = preparedStatement.executeQuery();

Ответ 2

            SELECT(" * ");
            FROM(" student ");
            WHERE(" ten LIKE '%' #{ten} '%' ");

Вы можете использовать его, и вы должны поместить пробел (_) между '%' и # {}