首頁 > 軟體

Mybatis實現動態排序方式

2022-10-26 14:02:46

Mybatis實現動態排序

在資料展示時,很有可能碰到,需要動態排序的需求。當資料比較少的時候,還可以前端排序,但是,當資料非常大,尤其是涉及到分頁的時候,就必須要用後端解決了。

以下,提供一種後端動態排序解決方案。

比如,現在我要查詢使用者資訊(User)表。

可以在查詢時,介面中,多新增兩個欄位。

  • orderField(排序列)
  • orderType(排序規則,升降序)

之後,在mapper.xml中的查詢列表方法,新增

SELECT 
name , sex , age , user_grade as userGrade
FROM user
<if test="orderField !=null and orderField != '' ">
    order by ${orderField}  ${orderType}
</if>

注意事項:使用這樣連續拼接兩個注入引數時,只能用${},不能用#{}。

詳情可以檢視解釋

這時,在我們查詢時,可以在傳入引數

User user = new User();
//以user_grade欄位排序
user.setOrderField("user_grade");
//降序
user.setOrderType("desc");
//可在User類中新增
//在未傳入時,使用set注入,設定預設值
public String getOrderField() {
        if (orderField == null || "".equals(orderField)) {
            orderField = "create_time";
        }
        return orderField;
    }
    public String getOrderType() {
        if (orderType == null || "".equals(orderType)) {
            orderType = "desc";
        }
        return orderType;
    }

如果,你覺得傳入資料庫中欄位user_grade很不舒服的話。可以這樣寫SQL

SELECT 
name , sex , age , user_grade as userGrade
FROM user
<if test="orderField != null" >
    ORDER BY
    <choose>
        <when test="orderField == 'name'">
            name ${orderType}
        </when>
        <when test="orderField == 'age'">
            age ${orderType}
        </when>
        <when test="orderField == 'userGrade'">
            user_grade ${orderType}
        </when>
        <otherwise>
            create_time ${orderType}
        </otherwise>
    </choose>
</if>

然後再傳入欄位時,就這樣

user.setOrderField("userGrade");

Mybatis動態排序不生效問題

sql如下:

select * from  table_name order by #{field}

造成問題原因

mybatis動態引數

#{}方式傳引數會使用preparedstatement預編譯處理方式,引數是以?預留位置的方式傳遞。可以看到mybaits的sql紀錄檔如下:

==> Preparing: SELECT * FROM table_name ORDER BY ?
==> Parameters: time(String)

preparedstatement預編譯方式的引數替換的原理1可知預編譯方式會對引數加上’'引號,生成的最終sql如下:

SELECT * FROM table_name ORDER BY 'time'

以上sql資料庫不能正常解析 order by 後面的欄位,這就是我們排序失效的原因

解決辦法

將#{}引數方式改成${}引數方式即可。

原因: ${}引數的方式是簡單的字串替換。

在動態解析階段,該 sql 語句會被解析成:

select * from table_name order by time

小結一下:

  • #{}方式傳引數只能處理值引數 不能傳遞表名,欄位等引數
  • ${}字串替換,可以動態處理表名,欄位引數,但是使用這種方式必須注意sql注入的風險,對引數做好校驗處理

備註:preparedstatement具體實現原理見:com.mysql.jdbc.PreparedStatement中的setString方法原始碼

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com