<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                mybatis 中使用 sqlMap 進行 sql 查詢時,經常需要動態傳遞參數,例如我們需要根據用戶的姓名來篩選用戶時,sql 如下: ~~~ select?*?from?user?where?name =?"ruhua"; ~~~ 上述 sql 中,我們希望 name 后的參數 "ruhua" 是動態可變的,即不同的時刻根據不同的姓名來查詢用戶。在 sqlMap 的 xml 文件中使用如下的 sql 可以實現動態傳遞參數 name: ~~~ select * from user where name = #{name}; ~~~ 或者 ~~~ select * from user where name = '${name}'; ~~~ 對于上述這種查詢情況來說,使用 #{ } 和${ } 的結果是相同的,但是在某些情況下,我們只能使用二者其一。 ## '#' 與 '$' ### 區別 **動態 SQL**是 mybatis 的強大特性之一,也是它優于其他 ORM 框架的一個重要原因。mybatis 在對 sql 語句進行預編譯之前,會對 sql 進行動態解析,解析為一個 BoundSql 對象,也是在此處對動態 SQL 進行處理的。 在動態 SQL 解析階段, #{ } 和${ } 會有不同的表現: > **#{ } 解析為一個 JDBC 預編譯語句(prepared statement)的參數標記符。** 例如,sqlMap 中如下的 sql 語句 ~~~ select?*?from?user?where?name?= #{name}; ~~~ 解析為: ~~~ select?*?from?user?where?name = ?; ~~~ 一個 #{ } 被解析為一個參數占位符`?`。 而, > **${ } 僅僅為一個純碎的 string 替換,在動態 SQL 解析階段將會進行變量替換** 例如,sqlMap 中如下的 sql ~~~ select?*?from?user?where?name =?'${name}'; ~~~ 當我們傳遞的參數為 "ruhua" 時,上述 sql 的解析為: ~~~ select?*?from?user?where?name =?"ruhua"; ~~~ 預編譯之前的 SQL 語句已經不包含變量 name 了。 綜上所得,${ } 的變量的替換階段是在動態 SQL 解析階段,而 #{ }的變量的替換是在 DBMS 中。 ### 用法 tips > 1、能使用 #{ } 的地方就用 #{ } 首先這是為了性能考慮的,相同的預編譯 sql 可以重復利用。 其次,**${ } 在預編譯之前已經被變量替換了,這會存在 sql 注入問題**。例如,如下的 sql, ~~~ select?*?from?${tableName}?where?name?= #{name} ~~~ 假如,我們的參數 tableName 為`user; delete user; --`,那么 SQL 動態解析階段之后,預編譯之前的 sql 將變為 ~~~ select?*?from?user;?delete?user; -- where name = ?; ~~~ `--`之后的語句將作為注釋,不起作用,因此本來的一條查詢語句偷偷的包含了一個刪除表數據的 SQL! > 2、表名作為變量時,必須使用${ } 這是因為,表名是字符串,使用 sql 占位符替換字符串時會帶上單引號`''`,這會導致 sql 語法錯誤,例如: ~~~ select?*?from?#{tableName}?where?name?= #{name}; ~~~ 預編譯之后的sql 變為: ~~~ select?*?from???where?name = ?; ~~~ 假設我們傳入的參數為 tableName = "user" , name = "ruhua",那么在占位符進行變量替換后,sql 語句變為 ~~~ select?*?from?'user'?where?name='ruhua'; ~~~ 上述 sql 語句是存在語法錯誤的,表名不能加單引號`''`(注意,反引號 ``是可以的)。 ## sql預編譯 ### 定義 > sql 預編譯指的是數據庫驅動在發送 sql 語句和參數給 DBMS 之前對 sql 語句進行編譯,這樣 DBMS 執行 sql 時,就不需要重新編譯。 ### 為什么需要預編譯 JDBC 中使用對象 PreparedStatement 來抽象預編譯語句,使用預編譯 1. **預編譯階段可以優化 sql 的執行**。 預編譯之后的 sql 多數情況下可以直接執行,DBMS 不需要再次編譯,越復雜的sql,編譯的復雜度將越大,預編譯階段可以合并多次操作為一個操作。 2. **預編譯語句對象可以重復利用**。 把一個 sql 預編譯后產生的 PreparedStatement 對象緩存下來,下次對于同一個sql,可以直接使用這個緩存的 PreparedState 對象。 mybatis 默認情況下,將對所有的 sql 進行預編譯。 ### mysql預編譯源碼解析 mysql 的預編譯源碼在`com.mysql.jdbc.ConnectionImpl`類中,如下: ~~~ public synchronized java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkClosed(); // // FIXME: Create warnings if can't create results of the given // type or concurrency // PreparedStatement pStmt = null; boolean canServerPrepare = true; // 不同的數據庫系統對sql進行語法轉換 String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql; // 判斷是否可以進行服務器端預編譯 if (this.useServerPreparedStmts && getEmulateUnsupportedPstmts()) { canServerPrepare = canHandleAsServerPreparedStatement(nativeSql); } // 如果可以進行服務器端預編譯 if (this.useServerPreparedStmts && canServerPrepare) { // 是否緩存了PreparedStatement對象 if (this.getCachePreparedStatements()) { synchronized (this.serverSideStatementCache) { // 從緩存中獲取緩存的PreparedStatement對象 pStmt = (com.mysql.jdbc.ServerPreparedStatement)this.serverSideStatementCache.remove(sql); if (pStmt != null) { // 緩存中存在對象時對原 sqlStatement 進行參數清空等 ((com.mysql.jdbc.ServerPreparedStatement)pStmt).setClosed(false); pStmt.clearParameters(); } if (pStmt == null) { try { // 如果緩存中不存在,則調用服務器端(數據庫)進行預編譯 pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency); if (sql.length() < getPreparedStatementCacheSqlLimit()) { ((com.mysql.jdbc.ServerPreparedStatement)pStmt).isCached = true; } // 設置返回類型以及并發類型 pStmt.setResultSetType(resultSetType); pStmt.setResultSetConcurrency(resultSetConcurrency); } catch (SQLException sqlEx) { // Punt, if necessary if (getEmulateUnsupportedPstmts()) { pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); if (sql.length() < getPreparedStatementCacheSqlLimit()) { this.serverSideStatementCheckCache.put(sql, Boolean.FALSE); } } else { throw sqlEx; } } } } } else { // 未啟用緩存時,直接調用服務器端進行預編譯 try { pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency); pStmt.setResultSetType(resultSetType); pStmt.setResultSetConcurrency(resultSetConcurrency); } catch (SQLException sqlEx) { // Punt, if necessary if (getEmulateUnsupportedPstmts()) { pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); } else { throw sqlEx; } } } } else { // 不支持服務器端預編譯時調用客戶端預編譯(不需要數據庫 connection ) pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false); } return pStmt; } ~~~ 流程圖如下所示: ![](https://img.kancloud.cn/62/03/620379a088e7c72a7cfd09bda4e90d72_890x766.png) ## mybatis之sql動態解析以及預編譯源碼 ### mybatis sql 動態解析 mybatis 在調用 connection 進行 sql 預編譯之前,會對sql語句進行動態解析,動態解析主要包含如下的功能: * 占位符的處理 * 動態sql的處理 * 參數類型校驗 mybatis強大的動態SQL功能的具體實現就在此
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看