Marcadores de posición MySql#{} y ${} detallados

${} es reemplazo de cadena. #{} es preprocesamiento

Al usar Mybatis para configurar declaraciones SQL, los parámetros en la declaración SQL pueden usar marcadores de posición en el formato de #{} , por ejemplo:

<select id="getStandardById" resultMap="StandardResultMap">
    SELECT
        <include refid="StandardQueryFields"/>
    FROM
        pms_album
    WHERE
        id=#{id}
</select>

De hecho, ¡también puede usar el marcador de posición ${} !

¡Para la configuración anterior, los marcadores de posición en el formato de #{} o ${} pueden pasar la prueba normalmente!

Además, use otra pieza de código para probar:

<select id="countByName" resultType="int">
    SELECT count(*) FROM pms_album WHERE name=#{name}
</select>

El código anterior puede pasar la prueba normalmente usando el marcador de posición en el formato de #{} , pero ocurre un error cuando se usa el marcador de posición en el formato de ${} :

Causa: java.sql.SQLSyntaxErrorException: Columna desconocida 'Álbum de Xiaomi 13' en 'cláusula where'; gramática SQL incorrecta []; la excepción anidada es java.sql.SQLSyntaxErrorException: Columna desconocida 'Álbum de Xiaomi 13' en 'cláusula where'

En el mensaje de error, podemos ver que el parámetro de prueba Xiaomi 13 album se usa como el nombre de la columna (nombre del campo) en la instrucción SQL .

De hecho, en las sentencias SQL, a excepción de contenido muy fijo como palabras clave, valores, operadores, nombres de funciones, etc., todo el contenido se considerará como un nombre determinado, como: nombre de tabla, nombre de campo u otros nombres personalizados (como como nombre de índice, etc.) , aplicaciones más típicas, como:

actualizar cuenta_bancaria establecer dinero = dinero + 1000 donde id = 1;

El significado de la instrucción SQL anterior es aproximadamente: aumentar el saldo de la cuenta con id=1 en 1000 sobre la base existente. Se puede ver que en el fragmento de código anterior de set money = money + 1000 , ¡ el dinero en el lado derecho del signo igual se considerará como el "nombre de campo"! Para evitar que MySQL trate el álbum de Mi 13 como un nombre de campo , se deben agregar un par de comillas simples en ambos lados del álbum de Mi 13, por ejemplo:

SELECCIONE el conteo (*) DESDE pms_album DONDE nombre='${nombre}'

Alternativamente, también es posible agregar un par de comillas simples alrededor de los datos de prueba:

String name = "'Álbum Mi 13'";

Por lo tanto, en una instrucción SQL, ¡solo los valores entre comillas dobles (excepto los valores numéricos) se considerarán "valores"!


Cuando MySQL procesa declaraciones SQL, pasará por análisis léxico, análisis semántico y luego compilará y finalmente ejecutará.

En Mybatis, se usarán marcadores de posición en el formato #{} en la implementación subyacente, y se usará el mecanismo de procesamiento de precompilación (que no tiene nada que ver con el valor del parámetro en el momento de la compilación), y el valor se sustituirá durante la ejecución. ! Debido al método de precompilación, todos los valores no necesitan considerar el tipo de datos. Por ejemplo, no es necesario agregar un par de comillas simples al valor del tipo de cadena, y la precompilación es segura, y habrá no hay problema de inyección de SQL! En este enfoque, el marcador de posición #{} solo puede representar un cierto valor en la instrucción SQL, ¡pero no otro contenido !

Usando marcadores de posición en el formato de ${} , cuando se implementa en la capa inferior, el valor se empalmará primero en la instrucción SQL original y luego se ejecutará el proceso de compilación relacionado. Dado que no está precompilado, es necesario agregar un par de comillas simples a los valores de cadenas, fechas, etc., de lo contrario, se considerarán como nombres de campo, expresiones de cálculo, etc. Ya que se sustituye el valor primero y luego se ejecuta el proceso relacionado con la compilación, los valores sustituidos pueden cambiar la semántica y existe el riesgo de inyección de SQL . En este enfoque, el marcador de posición ${} puede representar cualquier fragmento en la instrucción SQL, ¡siempre y cuando se pueda compilar después del empalme! Adjunto: demostración de inyección SQL:

select * from user where username='xxx' and password='xxxxxxxxxxxx';
--   												  1' or 'a'='a


select * from user where username='xxx' and password='1' or '1'='1';

Supongo que te gusta

Origin blog.csdn.net/weixin_72125569/article/details/126762388
Recomendado
Clasificación