HasorDB 參數(shù)與規(guī)則

2022-01-10 10:49 更新

在 映射文件 和 動態(tài) SQL 兩部分內(nèi)容中,看到了簡單的參數(shù)傳遞,例? #{age}?:

<select id="queryListByAge">
select * from `test_user` where age = #{age}
</select>

參數(shù)名是根據(jù) API 的調(diào)用時候穿入的,具體可以查閱 Mapper 接口,本節(jié)將會介紹 HasorDB 提供的三種不同參數(shù)傳遞方式。

  • ?#{...}? 動態(tài)參數(shù)。
  • ?${}? 字符串替換,使用時要小心 SQL 注入
  • ?@{} ?規(guī)則表達式,靈活使用規(guī)則可以減少大量 XML 配置。

動態(tài)參數(shù)?

在前面例子中 ?#{age}? 會獲取,當(dāng)前參數(shù)對象 的 ?age ?屬性,并將它的值傳遞給 ?PreparedStatement?。 這種傳參方式是標(biāo)準(zhǔn)做法,通常我們所指的 SQL 防注入也是通過動態(tài)參數(shù)來解決。

偶爾我們會希望參數(shù)類型以某個特定的 JDBC Type 來傳遞,那么就可以通過下列方式穿入。

#{property, jdbcType=NUMERIC}

也可以同時指定 ?jdbcType ?和 ?javaType?,設(shè)置它們最大的作用是可以幫助我們選擇適合的 類型處理器

#{property, javaType=int, jdbcType=NUMERIC}

有些時候需要指定 ?TypeHandler ?比如我們自定義的 ?TypeHandler?,可以選擇下面這種方式。

#{property, typeHandler=net.hasor.db.example.mapper.MyTypeHandler}

在執(zhí)行存儲過程通常需要指定輸入輸出參數(shù),可以通過 ?mode ?屬性設(shè)置為 out 來確定輸出參數(shù),比如:

{call proc_select_user(#{abc, mode=out})}

在調(diào)用存儲過程時 in 參數(shù) 和 out 參數(shù)都會通過在調(diào)用 API 時的參數(shù)來承載。mode 有三個取值 ?in?、?out?、?inout ?其中默認(rèn)是 ?in?

字符串替換?

默認(rèn)情況下,使用 ?#{}? 語法將會使用 ?PreparedStatement ?設(shè)置動態(tài)屬性。 雖然這樣更安全、更快,而且?guī)缀蹩偸鞘走x,但有時只想直接將未修改的字符串注入 SQL 語句。 例如,對于 ?order by?,你可以這樣使用:

order by ${columnName}

規(guī)則表達式?

規(guī)則表達式的寫法為 ?@{<規(guī)則名> [, <啟用條件OGNL> [, 規(guī)則內(nèi)容 ]]}?

一個規(guī)則最簡單的寫法只需要指明規(guī)則名即可,例如:

@{ruleName}

一個規(guī)則可以滿足某個條件才可以被使用,那么可以如下:

@{ruleName, age > 30}

有些規(guī)則本身在調(diào)用的時候要求穿入一些內(nèi)容。那么使用的方式如下:

@{ruleName, age > 30, xxxxxxx}

還可以使用下面方法省略條件參數(shù)如下:

@{ruleName,, xxxxxxx}

規(guī)則函數(shù)?

規(guī)則 描述
@{include, expr, sqlid} 效果和使用 <include refid="sqlid"/> 標(biāo)簽相同
@{ognl, expr, xxxx} 對 xxxx 進行 OGNL 求值,并把執(zhí)行結(jié)果加入到 SQL 參數(shù)中。類型讀寫請參考 類型映射
@{md5, expr, xxxx} 對 xxxx 進行 OGNL 求值,值結(jié)果用 MD5 進行編碼然后加入到 SQL 參數(shù)中
@{uuid32} 產(chǎn)生一個 32 字符長度的 UUID,并加入到 SQL 參數(shù)中
@{uuid36} 產(chǎn)生一個 36 字符長度的 UUID,并加入到 SQL 參數(shù)中
@{and, queryExpr} 快速'與'條件規(guī)則,詳細看下面
@{or, queryExpr} 快速'或'條件規(guī)則,詳細看下面
@{arg, expr, xxxx} xxxx 的寫法與 #{...} 中的內(nèi)容相同。這是一個內(nèi)置規(guī)則,#{...} 就是它的簡化形式
@{text, expr, xxxx} 原樣輸出 xxxx,這是一個內(nèi)置規(guī)則 HasorDB 內(nèi)部的一些機制會用到它。

快速條件拼接?

快速條件拼接包含 ?快速'與'條件? 和? 快速'或'條件 ?它們是兩個規(guī)則用于取代簡單的 ?if ?標(biāo)簽和簡單的 ?foreach ?標(biāo)簽。 如下語句,當(dāng)參數(shù)不為空時候才拼接 sql

<select id="queryUser">
select * from `test_user`
where 1 = 1
<if test="age != null">
and age = #{age}
</if>
</select>

可以簡化為快速規(guī)則寫法,其中? :age ?為屬性名。

<select id="queryUser">
select * from `test_user`
@{and, age = :age}
</select>

例如如下 ?foreach ?操作:

<select id="queryUser">
select * from `test_user`
where
id in <foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>

可以簡化為快速規(guī)則寫法,其中? :list ?為集合屬性名。

<select id="queryUser">
select * from `test_user`
@{and, id in (:list)}
</select>

如果多個簡單條件,快速寫法將會極大的減少 Mapper 的工作量。

<select id="queryByNameAndAge">
select * from `test_user`
@{and, age = :age}
@{and, name = :name}
@{and, id in (:ids)}
</select>

快速條件拼接(高級玩法)?

快速拼接規(guī)則的原理是利用 ?net.hasor.db.jdbc.core.ParsedSql? 工具類,將規(guī)則的條件表達式當(dāng)作 SQL 片段進行解析。 這部分和 ?JdbcTemplate? Map 傳參是等價的。

當(dāng) ?ParsedSql ?的 ?buildValues ?方法返回的參數(shù)全部為 ?null ?時快速拼接就會失效,反之則為有效的 SQL 片段。

因此快速拼接規(guī)則還可稍微復(fù)雜一點

@{and, (age = :age and sex = '1') or (name = :name and id in (:ids)) }

對應(yīng)的 SQL 為:

(age = ? and sex = '1') or (name = ? and id in (?, ?, ?))

自定義規(guī)則函數(shù)?

實現(xiàn)一個自定義的規(guī)則函數(shù)十分簡單只需要實現(xiàn) ?net.hasor.db.dal.dynamic.rule.SqlBuildRule? 接口并注冊到系統(tǒng)中就可以了。

public class MyRule implements SqlBuildRule {
public void executeRule(Map<String, Object> data, DynamicContext context,
SqlBuilder sqlBuilder, String activeExpr,
String ruleValue) {
...
SqlArg arg = new SqlArg(expr, value, sqlMode, jdbcType, javaType, typeHandler);
sqlBuilder.appendSql("?", arg);
}
}

注冊規(guī)則

RuleRegistry.DEFAULT.register("myrule", new MyRule());

最后就可以愉快的使用它了。

<select id="queryByNameAndAge">
select * from `test_user`
@{myrule, true, xxxx}
</select>


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號