mybatis批量操作出现BadSqlGrammarException问题解决

本文讲述了在XML配置文件中使用SQL批量插入时遇到的BadSqlGrammarException问题,通过调整数据库连接URL添加`allowMultiQueries=true`参数,解决了单条插入正常但多条数据插入失败的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

xml中SQL

    <insert id="batchInsertXxxInfo">
        <foreach collection="list" item="it" separator=";">
        insert into xxx_info
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="it.customerId != null">customer_id,</if>
            <if test="it.customerName != null and it.customerName != ''">customer_name,</if>
            <if test="it.customerPhone != null and it.customerPhone != ''">customer_phone,</if>
            <if test="it.createTime != null">create_time,</if>
            <if test="it.modifyTime != null">modify_time,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="it.customerId != null">#{it.customerId},</if>
            <if test="it.customerName != null and it.customerName != ''">#{it.customerName},</if>
            <if test="it.customerPhone != null and it.customerPhone != ''">#{it.customerPhone},</if>
            <if test="it.createTime != null">#{it.createTime},</if>
            <if test="it.modifyTime != null">#{it.modifyTime},</if>
        </trim>
        </foreach>
    </insert>

问题现象

单条插入没有问题,但是当有多条数据插入的时候就开始报BadSqlGrammarException异常

问题解决

数据库连接 url中加上&allowMultiQueries=true
原来连接:

url: jdbc:mysql://127.0.0.1:3306/fd_mgm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8

修改后连接:

url: jdbc:mysql://127.0.0.1:3306/fd_mgm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
<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个

红包金额最低5元

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

抵扣说明:

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

余额充值