简介:iBatis框架中#与$符号的参数处理差异是开发者高频疑问,本文从SQL注入防护、参数类型处理、动态SQL生成等维度展开技术解析,结合实际场景说明两种符号的适用边界,并提供参数安全加固方案。
在iBatis(现MyBatis前身)的SQL映射文件中,#和$符号作为参数占位符的核心差异体现在参数处理方式、安全机制及动态SQL生成能力三个层面。这两种符号的选择直接影响SQL语句的执行效率与安全性,是开发者必须掌握的关键技术点。
<select id="getUserById" resultType="User">SELECT * FROM users WHERE id = #{userId}</select>
执行时生成的SQL为:SELECT * FROM users WHERE id = ?,参数通过setInt()等方法安全注入。
$符号采用直接字符串替换方式,在SQL生成阶段完成参数值嵌入:
<select id="getUserByOrder" resultType="User">SELECT * FROM users ORDER BY ${orderColumn}</select>
若传入orderColumn=”name DESC”,最终SQL为:SELECT * FROM users ORDER BY name DESC
| 机制 | #符号防护效果 | $符号防护效果 | 典型攻击场景防御 |
|---|---|---|---|
| 数值参数 | 完全防护 | 完全暴露 | 1 OR 1=1注入 |
| 字符串参数 | 自动转义 | 直接拼接 | ‘;DROP TABLE—注入 |
| 动态表名 | 不适用 | 需白名单验证 | 表名注入攻击 |
// 使用#符号时自动类型转换userMapper.getUserById(123); // 自动转为整数// 使用$符号时需字符串匹配userMapper.getUserByOrder("name DESC"); // 必须精确匹配SQL语法
$符号在需要动态指定数据库对象时具有不可替代性:
<select id="getDynamicData" resultType="Map">SELECT ${columns} FROM ${tableName}WHERE ${condition} = #{value}</select>
需配合参数校验:
public List<Map> getDynamicData(String columns, String tableName, String condition, Object value) {// 实现表名/列名的白名单校验if (!isValidTableName(tableName)) throw new IllegalArgumentException();// ...}
$符号是实现动态排序的标准方案:
<select id="getUsers" resultType="User">SELECT * FROM usersORDER BY ${sortField} ${sortOrder}</select>
安全实现建议:
public List<User> getUsers(String sortField, String sortOrder) {// 参数校验Set<String> validFields = Set.of("id", "name", "create_time");Set<String> validOrders = Set.of("ASC", "DESC");if (!validFields.contains(sortField) || !validOrders.contains(sortOrder)) {throw new IllegalArgumentException("Invalid sort parameters");}// 调用Mapper}
测试数据显示,在1000次循环查询中:
<select id="getPaginatedUsers" resultType="User">SELECT * FROM usersWHERE department_id = #{deptId}ORDER BY ${sortField} ${sortOrder}LIMIT #{offset}, #{pageSize}</select>
该模式实现:
MyBatis 3.x提供的@Select等注解方式,可结合Java类型系统增强安全性:
@Select("SELECT * FROM ${tableName} WHERE id = #{id}")List<User> getUsersByTable(@Param("tableName") String tableName, @Param("id") Long id);
某金融系统案例显示,实施上述措施后,SQL注入漏洞数量下降82%,同时保持了必要的业务灵活性。
理解并正确应用#与$的差异,是构建安全高效数据访问层的基础。开发者应根据具体业务场景,在安全性与灵活性之间取得最佳平衡。