Heim  >  Artikel  >  Java  >  Was sind die Unterschiede zwischen ${} und #{} in Java?

Was sind die Unterschiede zwischen ${} und #{} in Java?

王林
王林nach vorne
2023-05-01 13:52:063860Durchsuche

    Vorwort

    ${} und #{} werden beide als Ersatz in MyBatis verwendet Parameter können die vom Benutzer an die schließlich von MyBatis generierte SQL übergebenen Parameter ersetzen, aber ihre Unterschiede sind sehr groß. Schauen wir uns das gemeinsam an. ${} 和 #{} 都是 MyBatis 中用来替换参数的,它们都可以将用户传递过来的参数,替换到 MyBatis 最终生成的 SQL 中,但它们区别却是很大的,接下来我们一起来看。

    1.功能不同

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

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

    最终生成的执行 SQL 如下: 

    Was sind die Unterschiede zwischen ${} und #{} in Java?

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

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

    最终生成的 SQL 如下: 

    Was sind die Unterschiede zwischen ${} und #{} in Java?

    1.1 ${} 的问题

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

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

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

    Was sind die Unterschiede zwischen ${} und #{} in Java?

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

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

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

    Was sind die Unterschiede zwischen ${} und #{} in Java?

    2.使用场景不同

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

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

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

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

    Was sind die Unterschiede zwischen ${} und #{} in Java?

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

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

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

    Was sind die Unterschiede zwischen ${} und #{} in 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 和运行结果如下: 

    Was sind die Unterschiede zwischen ${} und #{} in Java?

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

    1. Verschiedene Funktionen

    ${} ist das direkte Ersetzen von Parametern in SQL

    ,

    Zum Beispiel der folgende Code: #🎜 🎜#Was sind die Unterschiede zwischen ${} und #{} in Java?

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

    #🎜🎜#Das endgültig generierte Ausführungs-SQL lautet wie folgt: #🎜🎜##🎜🎜##🎜🎜#Was sind die Unterschiede zwischen ${} und #{} in Java#🎜🎜##🎜🎜# Wie Sie sehen können Im Bild oben wird der vorherige Parameter $ {id} direkt durch den spezifischen Parameterwert 1 ersetzt. #🎜🎜##{} verwendet Platzhalter und Vorverarbeitung, um das Geschäft #🎜🎜# auszuführen. Wir wandeln den obigen Fall in die Form von #{} um, #🎜🎜#Der Implementierungscode lautet wie folgt:#🎜🎜##🎜🎜 #
    <select id="login" resultType="com.example.demo.model.UserInfo">
      select * from userinfo where name=#{name} and password=#{password}
    </select>
    #🎜🎜##🎜🎜#Das endgültig generierte SQL lautet wie folgt: #🎜🎜##🎜🎜##🎜🎜#Was sind die Unterschiede zwischen ${} und #{} in Java#🎜🎜#

    1.1 ${} Problem

    #🎜🎜#Wann Der Parameter ist ein numerischer Typ (ohne Berücksichtigung von Sicherheitsproblemen). Die Ausführungseffekte von ${} und #{} sind jedoch dieselben. Wenn der Parametertyp jedoch ein Zeichen ist, gilt bei Verwendung von ${}. Es wird ein Problem auftreten. #🎜🎜#Der folgende Code wird angezeigt: #🎜🎜##🎜🎜#
    @Test
    void login() {
        UserInfo userInfo = userMapper.login("java", "&#39; or 1=&#39;1");
        System.out.println(userInfo);
    }
    #🎜🎜##🎜🎜#Wenn das obige Programm ausgeführt wird, lautet die generierte SQL-Anweisung wie folgt: # 🎜 🎜##🎜🎜##🎜🎜#${}und# in Java { }Was sind die Unterschiede?#🎜🎜##🎜🎜# Dies führt dazu, dass das Programm einen Fehler meldet, da die übergebenen Parameter vom Typ Zeichen sind und in der SQL-Syntax, wenn es sich um einen Zeichentyp handelt, einfache Anführungszeichen sind müssen zum Wert hinzugefügt werden, andernfalls wird ein Fehler gemeldet und ${} ist ein direkter Ersatz und einfache Anführungszeichen werden nicht automatisch hinzugefügt, sodass bei der Ausführung ein Fehler gemeldet wird. Die Verwendung von #{} verwendet Platzhalter vor der Ausführung, sodass kein Problem besteht. Der Implementierungscode lautet wie folgt: #🎜🎜#rrreee#🎜🎜##🎜🎜#Die vom obigen Programm letztendlich generierte Ausführungs-SQL lautet wie folgt : # 🎜🎜##🎜🎜##🎜🎜#${}and# in Java Was sind die Unterschiede zwischen {}#🎜🎜##🎜🎜#2. Verschiedene Verwendungsszenarien#🎜🎜##🎜🎜#Obwohl die #{}-Methode jede Art von Parametern verarbeiten kann, wenn sie übergeben wird Parameter ist ein Problem mit #{}, wenn SQL-Befehle oder SQL-Schlüsselwörter verwendet werden. Wenn wir beispielsweise nach dem Preis von hoch nach niedrig (umgekehrte Reihenfolge) oder von niedrig nach hoch (vorwärts) abfragen möchten #🎜🎜##🎜🎜# Zu diesem Zeitpunkt möchten wir das Sortierschlüsselwort desc in umgekehrter Reihenfolge übergeben ( Preis von hoch nach niedrig) oder aufsteigende positive Sequenz (Preis von niedrig nach hoch), zu diesem Zeitpunkt verwenden wir den Implementierungscode von ${} Ruian: #🎜🎜#rrreee#🎜🎜##🎜 🎜# oben Die vom Code generierten Ausführungs-SQL- und Laufergebnisse lauten wie folgt: #🎜🎜##🎜🎜##🎜🎜#Was sind die Unterschiede zwischen ${} und #{} in Java#🎜🎜##🎜🎜##🎜🎜# Allerdings, wenn ${} im Code ist in #{} geändert, dann wird das Programm ausgeführt. Der Implementierungscode von #{} lautet wie folgt: #🎜🎜##🎜🎜#rrreee#🎜🎜##🎜🎜#Die Ausführung von SQL Die durch den obigen Code generierten Ergebnisse lauten wie folgt: #🎜🎜##🎜🎜##🎜 🎜#Was sind die Unterschiede zwischen ${} und #{} in Java# 🎜🎜##🎜🎜##🎜🎜# Aus den obigen Ausführungsergebnissen können wir Folgendes sehen: #🎜🎜#Bei der Übergabe gewöhnlicher Parameter , müssen Sie die #{}-Methode verwenden und bei der Übergabe von SQL-Befehlen oder SQL-Schlüsselwörtern ${} verwenden, um die Parameter direkt in SQL zu ersetzen und auszuführen. #🎜🎜##🎜🎜#3. Unterschiedliche Sicherheit #🎜🎜##🎜🎜#${} und #{} Der Hauptunterschied spiegelt sich im Sicherheitsaspekt wider {} verursacht Sicherheitsprobleme, d. h. SQL-Injection-Probleme, während die Verwendung von #{} keine Sicherheitsprobleme verursacht, da es vorverarbeitet wird. Schauen wir uns den Unterschied zwischen den beiden anhand der folgenden Anmeldefunktion an. #🎜🎜#

    3.1 Verwenden Sie ${}, um die Benutzeranmeldung zu implementieren

    #🎜🎜##🎜🎜#Der Implementierungscode in UserMapper.xml lautet wie folgt: #🎜🎜##🎜🎜#rrreee#🎜 🎜## 🎜🎜#Der Unit-Test-Code lautet wie folgt: #🎜🎜##🎜🎜#rrreee#🎜🎜##🎜🎜#Die durch den obigen Code generierten Ausführungs-SQL- und Laufergebnisse lauten wie folgt: #🎜🎜# #🎜🎜##🎜🎜#Was sind die Unterschiede zwischen ${} und # {} in java#🎜🎜## 🎜🎜# Aus den Ergebnissen geht hervor, dass wir die Daten erfolgreich abfragen können, wenn wir den richtigen Benutzernamen und das richtige Passwort übergeben. Wenn wir jedoch ${} verwenden und das richtige Passwort nicht kennen, können wir auch SQL-Injection-Anweisungen verwenden, um die privaten Informationen des Benutzers abzurufen. Der Implementierungscode der SQL-Injection lautet wie folgt: # 🎜🎜# rrreee#🎜🎜##🎜🎜#Die durch den obigen Code generierten Ausführungs-SQL- und Laufergebnisse lauten wie folgt: #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#

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

    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 和执行结果如下: 

    Was sind die Unterschiede zwischen ${} und #{} in Java?

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

    Das obige ist der detaillierte Inhalt vonWas sind die Unterschiede zwischen ${} und #{} in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen