MyBatis动态传入表名,字段名参数的解决办法

原文:http://luoyu-ds.iteye.com/blog/1517607

要实现动态传入表名、列名,需要做如下修改

  • 添加属性statementType="STATEMENT"
  • 同时sql里的属有变量取值都改成${xxxx},而不是#{xxx}

<delete id="deleteTableData" parameterType="java.util.Map" statementType="STATEMENT">
	<![CDATA[
		delete from ${table} where
		${col} < ${date}]]>
</delete>

1. statementType:STATEMENT(非预编译),PREPARED(预编译)或CALLABLE中的任意一个,这就告诉 MyBatis 分别使用Statement,PreparedStatement或者CallableStatement。默认:PREPARED。这里显然不能使用预编译,要改成非预编译。

2. ${xxxx}:$将传入的数据直接显示生成在sql中,对于字符串数据,需要手动加上引号。

String dateStr = DateFormatUtils.format(date.getTime(), "yyyy-MM-dd HH:mm:ss");
dateStr = "'" + dateStr + "'";


<think>嗯,用户想知道如何在MyBatis动态调用字段名。我需要根据提供的引用资料整理出一个清晰的步骤。首先,用户可能遇到需要根据不同条件切换或字段的情况,比如多租户系统或者动态权限控制。根据引用[2]和[4],动态表字段名需要使用${}占位符,因为#{}会预编译成带引号的字符串,导致SQL语法错误。但要注意${}可能带来的SQL注入风险,所以需要确保传入参数的安全性。 然后,引用[4]提到需要设置statementType="PREPARED",但默认就是PREPARED,可能在某些情况下需要显式设置。比如在动态表中使用${}时,可能还需要保持其他条件参数使用#{}以防止注入。另外,动态SQL可能需要结合<if>标签或者<foreach>来处理不同的情况,比如引用中的例子用foreach批量删除不同的记录。 还要注意,MyBatis在处理${}时不会进行预编译,而是直接替换,所以字段名不能有特殊字符,需要手动处理。引用[5]提到异常处理,比如捕获BadSqlGrammarException来自动建,这可能是在动态表不存在时的处理策略,但需要确保异常原因准确,避免误判。 用户可能需要示例代码,所以应该给出XML配置和Java代码的例子,展示如何传递参数和使用${}。同时,安全问题很重要,必须提醒用户对传入字段名进行校验,比如白单机制,避免任意输入导致注入攻击。 最后,相关问题的生成要考虑用户可能的后续疑问,比如安全性、性能优化、动态排序等,这样能帮助用户更全面地应用动态SQL功能。</think>### MyBatis动态调用字段名的实现方法 在MyBatis动态调用字段名需通过**非预编译参数占位符**(`${}`)实现,结合`statementType`属性配置和动态SQL标签。以下是具体实现步骤及注意事项: --- #### 一、核心实现原理 1. **`#{}`与`${}`的区别** - `#{}`是预编译参数占位符,会转义为`?`并添加引号,适合传递**值类型**参数(如`WHERE id = #{id}`)[^4] - `${}`是直接替换占位符,适合传递**数据库对象**(如字段名),例如:`SELECT * FROM ${tableName}`[^2] 2. **`statementType`属性** 通过设置`statementType="STATEMENT"`(非预编译)或`statementType="PREPARED"`(默认值)控制SQL处理方式[^4]。动态表场景建议保持默认`PREPARED`模式,仅对字段使用`${}`。 --- #### 二、具体实现步骤 ##### 1. Mapper XML配置示例 ```xml <!-- 动态表查询 --> <select id="selectByDynamicTable" resultType="map" statementType="PREPARED"> SELECT ${columnName} FROM ${tableName} WHERE id = #{id} </select> <!-- 动态字段批量操作 --> <delete id="deleteByDynamicCondition" statementType="PREPARED"> DELETE FROM ${tableName} WHERE ${filterColumn} IN <foreach item="item" collection="values" open="(" separator="," close=")"> #{item} </foreach> </delete> ``` ##### 2. Java参数传递方式 ```java // 使用Map传递动态参数 Map<String, Object> params = new HashMap<>(); params.put("tableName", "user_table"); params.put("columnName", "username,email"); params.put("id", 1001); List<Map<String, Object>> result = sqlSession.selectList("selectByDynamicTable", params); ``` ##### 3. 动态SQL组合 ```xml <!-- 条件判断动态字段 --> <select id="dynamicFieldQuery" resultType="map"> SELECT <choose> <when test="role == 'admin'">*, secret_field</when> <otherwise>id, name, public_field</otherwise> </choose> FROM ${tableName} </select> ``` --- #### 三、安全注意事项 1. **输入验证** 必须对传入的`tableName`和`columnName`进行白单校验,防止SQL注入: ```java // 校验示例 private static final Set<String> ALLOWED_TABLES = Set.of("user", "order"); if (!ALLOWED_TABLES.contains(tableName)) { throw new IllegalArgumentException("Invalid table name"); } ``` 2. **防御性处理** - 对动态字段/使用反引号包裹:`` `$${tableName}` `` - 避免直接拼接用户输入内容 --- #### 四、典型应用场景 1. 多租户系统中动态切换分(如`user_tenant1`, `user_tenant2`)[^1] 2. 数据权限控制(根据角色动态屏蔽字段)[^2] 3. 通用DAO层实现(同一方法操作不同结构)[^5] ---
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值