在 映射文件 和 動態(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 配置。在前面例子中 ?#{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ī)則名> [, <啟用條件OGNL> [, 規(guī)則內(nèi)容 ]]}
?
一個規(guī)則最簡單的寫法只需要指明規(guī)則名即可,例如:
@{ruleName}
一個規(guī)則可以滿足某個條件才可以被使用,那么可以如下:
@{ruleName, age > 30}
有些規(guī)則本身在調(diào)用的時候要求穿入一些內(nèi)容。那么使用的方式如下:
@{ruleName, age > 30, xxxxxxx}
還可以使用下面方法省略條件參數(shù)如下:
@{ruleName,, xxxxxxx}
規(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 (?, ?, ?))
實現(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>
更多建議: