Maison  >  Article  >  Java  >  Quelles sont les différences entre ${} et #{} en Java ?

Quelles sont les différences entre ${} et #{} en Java ?

王林
王林avant
2023-05-01 13:52:063860parcourir

    Preface

    ${} et #{} sont tous deux utilisés pour le remplacement dans MyBatis Paramètres, ils peuvent remplacer les paramètres passés par l'utilisateur dans le SQL finalement généré par MyBatis, mais leurs différences sont très grandes, regardons ensemble. ${} 和 #{} 都是 MyBatis 中用来替换参数的,它们都可以将用户传递过来的参数,替换到 MyBatis 最终生成的 SQL 中,但它们区别却是很大的,接下来我们一起来看。

    1.功能不同

    ${} 是将参数直接替换到 SQL 中比如以下代码:

    <select id="getUserById" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where id=${id}
    </select>

    最终生成的执行 SQL 如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     从上图可以看出,之前的参数 ${id} 被直接替换成具体的参数值 1 了。 而 #{} 则是使用占位符的方式,用预处理的方式来执行业务,我们将上面的案例改造为 #{} 的形式,实现代码如下:

    <select id="getUserById" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where id=#{id}
    </select>

    最终生成的 SQL 如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

    1.1 ${} 的问题

    当参数为数值类型时(在不考虑安全问题的前提下),${} 和 #{} 的执行效果都是一样的,然而当参数的类型为字符时,再使用 ${} 就有问题了,如下代码所示:

    <select id="getUserByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where name=${name}
    </select>

    以上程序执行时,生成的 SQL 语句如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     这样就会导致程序报错,因为传递的参数是字符类型的,而在 SQL 的语法中,如果是字符类型需要给值添加单引号,否则就会报错,而 ${} 是直接替换,不会自动添加单引号,所以执行就报错了。 而使用 #{} 采用的是占位符预执行的,所以不存在任何问题,它的实现代码如下:

    <select id="getUserByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where name=#{name}
    </select>

    以上程序最终生成的执行 SQL 如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

    2.使用场景不同

    虽然使用 #{} 的方式可以处理任意类型的参数,然而当传递的参数是一个 SQL 命令或 SQL 关键字时 #{} 就会出问题了。比如,当我们要根据价格从高到低(倒序)、或从低到高(正序)查询时

    此时我们要传递的排序的关键字,desc 倒序(价格从高到低)或者是 asc 正序(价格从低到高),此时我们使用 ${} 的实现代码瑞安:

    <select id="getAll" resultType="com.example.demo.model.Goods">
      select * from goods order by price ${sort}
    </select>

    以上代码生成的执行 SQL 和运行结果如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     但是,如果将代码中的 ${} 改为 #{},那么程序执行就会报错,#{} 的实现代码如下:

    <select id="getAll" resultType="com.example.demo.model.Goods">
      select * from goods order by price #{sort}
    </select>

    以上代码生成的执行 SQL 和运行结果如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     从上述的执行结果我们可以看出:当传递的是普通参数时,需要使用 #{} 的方式,而当传递的是 SQL 命令或 SQL 关键字时,需要使用 ${} 来对 SQL 中的参数进行直接替换并执行。

    3.安全性不同

    ${} 和 #{} 最主要的区别体现在安全方面,当使用 ${} 会出现安全问题,也就是 SQL 注入的问题,而使用 #{} 因为是预处理的,所以不会存在安全问题,我们通过下面的登录功能来观察一下二者的区别。

    3.1 使用 ${} 实现用户登录

    UserMapper.xml 中的实现代码如下:

    <select id="login" resultType="com.example.demo.model.UserInfo">
      select * from userinfo where name=&#39;${name}&#39; and password=&#39;${password}&#39;
    </select>

    单元测试代码如下:

    @Test
    void login() {
        UserInfo userInfo = userMapper.login("java", "java");
        System.out.println(userInfo);
    }

    以上代码生成的执行 SQL 和运行结果如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     从结果可以看出,当我们传入了正确的用户名和密码时,能成功的查询到数据。但是,在我们使用 ${}

    1. Différentes fonctions

    ${} consiste à remplacer directement les paramètres dans SQL

    ,

    Par exemple, le code suivant : #🎜 🎜#Quelles sont les différences entre ${} et #{} en Java ?

    @Test
    void login() {
        UserInfo userInfo = userMapper.login("java", "&#39; or 1=&#39;1");
        System.out.println(userInfo);
    }

    #🎜🎜#Le SQL d'exécution final généré est le suivant : #🎜🎜##🎜🎜##🎜🎜#Quelles sont les différences entre ${} et #{} en java#🎜🎜##🎜🎜# Comme vous pouvez le voir sur Dans l'image ci-dessus, le paramètre précédent $ {id} est directement remplacé par la valeur de paramètre spécifique 1. #🎜🎜##{} utilise des espaces réservés et un prétraitement pour exécuter les affaires #🎜🎜# Nous transformons le cas ci - dessus en #{}, #🎜🎜#Le code d'implémentation est le suivant:#🎜🎜##🎜🎜. #
    <select id="login" resultType="com.example.demo.model.UserInfo">
      select * from userinfo where name=#{name} and password=#{password}
    </select>
    #🎜🎜##🎜🎜#Le SQL final généré est le suivant : #🎜🎜##🎜🎜##🎜🎜#Quelles sont les différences entre ${} et #{} en java#🎜🎜#

    1.1 problème ${}

    #🎜🎜#Quand le paramètre est de type numérique (sans tenir compte des problèmes de sécurité), les effets d'exécution de ${} et #{} sont les mêmes. Cependant, lorsque le type de paramètre est un caractère lors de l'utilisation de ${}, il y aura un problème. #🎜🎜#Le code suivant est affiché : #🎜🎜##🎜🎜#
    @Test
    void login() {
        UserInfo userInfo = userMapper.login("java", "&#39; or 1=&#39;1");
        System.out.println(userInfo);
    }
    #🎜🎜##🎜🎜#Lorsque le programme ci-dessus est exécuté, l'instruction SQL générée est la suivante : # 🎜 🎜##🎜🎜##🎜🎜#${}et# en java { }Quelles sont les différences ?#🎜🎜##🎜🎜# Cela entraînera le rapport d'une erreur par le programme, car les paramètres passés sont de type caractère, et dans la syntaxe SQL, s'il s'agit d'un type de caractère, des guillemets simples doit être ajouté à la valeur. Sinon, une erreur sera signalée, et ${} est un remplacement direct et les guillemets simples ne seront pas automatiquement ajoutés, donc une erreur sera signalée lors de l'exécution. L'utilisation de #{} utilise la pré-exécution d'un espace réservé, il n'y a donc aucun problème. Son code d'implémentation est le suivant : #🎜🎜#rrreee#🎜🎜##🎜🎜#Le SQL d'exécution finalement généré par le programme ci-dessus est le suivant. : # 🎜🎜##🎜🎜##🎜🎜#${}et# en java Quelles sont les différences entre {}#🎜🎜##🎜🎜#2. Différents scénarios d'utilisation#🎜🎜##🎜🎜#Bien que l'utilisation de la méthode #{} puisse gérer tout type de paramètres, lorsque le passé Le paramètre est un Il y aura un problème avec #{} lors de l'utilisation de commandes SQL ou de mots-clés SQL. Par exemple, lorsque nous voulons interroger du haut vers le bas (ordre inversé) ou du bas vers le haut (ordre direct) par prix #🎜🎜##🎜🎜# À ce stade, nous voulons transmettre le mot-clé de tri, desc ordre inverse ( prix de haut en bas) ou séquence positive asc (prix de bas en haut), nous utilisons actuellement le code d'implémentation de ${} Ruian : #🎜🎜#rrreee#🎜🎜##🎜 🎜# ci-dessus Les résultats d'exécution SQL et d'exécution générés par le code sont les suivants : #🎜🎜##🎜🎜##🎜🎜#Quelles sont les différences entre ${} et #{} en java#🎜🎜##🎜🎜##🎜🎜# Cependant, si ${} dans le code est changé en #{}, alors le programme s'exécutera. Une erreur sera signalée. Le code d'implémentation de #{} est le suivant : #🎜🎜##🎜🎜#rrreee#🎜🎜##🎜🎜#L'exécution SQL et en cours d'exécution. les résultats générés par le code ci-dessus sont les suivants : #🎜🎜##🎜🎜##🎜 🎜#Quelles sont les différences entre ${} et #{} en java# 🎜🎜##🎜🎜##🎜🎜# À partir des résultats d'exécution ci-dessus, nous pouvons voir : #🎜🎜#Lors du passage de paramètres ordinaires , vous devez utiliser la méthode #{}, et lors du passage de commandes SQL ou d'un mot-clé SQL, vous devez utiliser ${} pour remplacer et exécuter directement les paramètres dans SQL. #🎜🎜##🎜🎜#3. Sécurité différente #🎜🎜##🎜🎜#${} et #{} La principale différence se reflète dans l'aspect sécurité lors de l'utilisation de $. {} provoquera des problèmes de sécurité, c'est-à-dire des problèmes d'injection SQL, tandis que l'utilisation de #{} ne posera pas de problèmes de sécurité car il est prétraité. Observons la différence entre les deux via la fonction de connexion ci-dessous. #🎜🎜#

    3.1 Utilisez ${} pour implémenter la connexion utilisateur

    #🎜🎜##🎜🎜#Le code d'implémentation dans UserMapper.xml est le suivant : #🎜🎜##🎜🎜#rrreee#🎜 🎜## 🎜🎜#Le code du test unitaire est le suivant : #🎜🎜##🎜🎜#rrreee#🎜🎜##🎜🎜#Le SQL d'exécution et les résultats d'exécution générés par le code ci-dessus sont les suivants : #🎜🎜# #🎜🎜##🎜🎜#Quelles sont les différences entre ${} et # {} en java#🎜🎜## 🎜🎜# Il ressort des résultats que lorsque nous transmettons le nom d'utilisateur et le mot de passe corrects, nous pouvons interroger les données avec succès. Cependant, lorsque nous utilisons ${}, lorsque nous ne connaissons pas le bon mot de passe, nous pouvons également utiliser des instructions d'injection SQL pour obtenir les informations privées de l'utilisateur. Le code d'implémentation de l'injection SQL est le suivant : # 🎜🎜#rrreee#🎜🎜##🎜🎜#Le SQL d'exécution et les résultats d'exécution générés par le code ci-dessus sont les suivants : #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#

     从上述结果可以看出,当使用 ${} 时,在不知道正确密码的情况下也能得到用户的私人数据,这就像一个小偷在没有你们家钥匙的情况下,也能轻松的打开你们家大门一样,这是何其恐怖的事情。那使用 #{} 有没有安全问题呢?接下来我们来测试一下。

    3.2 使用 #{} 实现用户登录

    首先将 UserMapper.xml 中的代码改成以下内容:

    <select id="login" resultType="com.example.demo.model.UserInfo">
      select * from userinfo where name=#{name} and password=#{password}
    </select>

    接着我们使用上面的 SQL 注入来测试登录功能:

    @Test
    void login() {
        UserInfo userInfo = userMapper.login("java", "&#39; or 1=&#39;1");
        System.out.println(userInfo);
    }

    最终生成的 SQL 和执行结果如下: 

    Quelles sont les différences entre ${} et #{} en Java ?

     从上述代码可以看出,使用 SQL 注入是无法攻破 #{} 的“大门”的,所以可以放心使用。

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer