mysql 字符串分割 和 动态执行拼接sql

本文介绍了一个MySQL存储过程的实现案例,涉及字符串分割及动态SQL执行。通过使用REVERSE和SUBSTRING_INDEX函数完成字符串分割,并利用PREPARE和EXECUTE语句实现动态SQL更新操作。

人以前主要用的是MSSQL,最近项目在使用MYSQL,自己是一个 典型的小白。今天就记录一下 一个mysql存储过程,里面需要分割字符串和 动态执行sql语句。

关于字符串 分割我开始使用 LOCATE 和Position来做,不知道在proc 里面有时候报错,单独的查询有可以。后来在网上 找了一个 Mysql存储过程中字符串分割文章, 很多地方都推荐使用  SET @result = REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(plate_sku_name,',',i)),',',1));   

至于执行sql 则需要  PREPARE sql1 FROM @sql1;  EXECUTE sql1;   感觉也比MSSQL复杂。

DELIMITER $$   
  
DROP PROCEDURE IF EXISTS simple_while$$   
  
CREATE PROCEDURE simple_while(IN period_no VARCHAR(7), IN all_test_id TEXT, OUT return_count INT)  
BEGIN   
  SET return_count=0;
  SET @i=0;
  SET @arraylength=1+(LENGTH(all_test_id) - LENGTH(REPLACE(all_test_id,',','')));  
    WHILE @i<@arraylength  
        DO  
        SET @i=@i+1;  
        SET @result = REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(all_test_id,',',@i)),',',1));   
        SET @sql=CONCAT('Update test_',period_no,' Set is_cancel = 1 WHERE all_test_id = ',@result);
       PREPARE sql1 FROM @sql;  
       EXECUTE sql1;  
       SET return_count=return_count+ ROW_COUNT();
    END WHILE;    
      
END$$
  
DELIMITER ;

 

### MyBatis 使用 `<foreach>` 标签时 SQL 拼接长度的限制及解决方案 在使用 MyBatis 的 `<foreach>` 标签生成动态 SQL 语句时,可能会遇到因 SQL 长度过大而导致的语法错误或其他异常情况。这种问题通常与数据库本身的 SQL 查询长度限制有关。 #### 数据库层面的 SQL 长度限制 MySQL 对单条 SQL 语句的最大长度有严格的限制,默认情况下最大允许的包大小由 `max_allowed_packet` 参数控制[^1]。如果生成的 SQL 过长,则可能触发以下错误: - **SQLSyntaxErrorException**: 表明 SQL 语法存在问题,可能是由于过长的字符串未被正确解析。 可以通过调整 MySQL 配置文件中的 `max_allowed_packet` 值来增加支持的最大 SQL 长度。默认值通常是 4MB 或 16MB,具体取决于版本配置。修改方法如下: ```bash [mysqld] max_allowed_packet=1073741824 # 设置为 1GB ``` 重启 MySQL 后生效,并可通过命令验证设置是否成功: ```sql SHOW VARIABLES LIKE 'max_allowed_packet'; ``` #### MyBatis 层面的优化策略 尽管增大数据库端的限制可以解决问题,但在实际开发中更推荐从应用层面对数据量进行拆分优化,从而减少超长 SQL 的可能性。以下是几种常见的解决方案: 1. **分批处理** 如果需要插入或查询大量数据,可考虑将集合按固定数量分割成多个子集分别执行操作。例如,在 Java 中实现逻辑分页并多次调用 Mapper 方法完成任务。 ```java public void batchProcess(List<String> ids) { int batchSize = 1000; List<List<String>> partitions = Lists.partition(ids, batchSize); for (List<String> partition : partitions) { mapper.batchInsert(partition); // 执行每一批次的操作 } } ``` 2. **临时表替代 IN 子句** 当条件列表特别庞大时(如超过几千项),直接使用 `IN (...)` 可能效率低下甚至失败。此时可以在程序中先创建一个临时表存储目标 ID 列表,再通过 JOIN 方式关联主表获取所需记录。 ```xml <!-- 插入到临时表 --> INSERT INTO temp_table (id_column) VALUES <foreach collection="list" item="item" separator=","> (#{item}) </foreach>; <!-- 主查询 --> SELECT * FROM main_table mt INNER JOIN temp_table tt ON mt.id = tt.id_column; ``` 3. **预编译参数化查询** 将原始字符串形式的输入转换为数组后逐个绑定变量传递给 PreparedStatement 处理,这样不仅规避了潜在的安全隐患还能有效缩短最终提交至服务器端的实际脚本尺寸。 ```xml <if test="step != null and step != ''"> AND step IN <foreach collection="step.split(',' )" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> ``` 上述方式利用正则表达式对传参做初步切割后再逐一映射成为独立占位符位置,既保持灵活性又兼顾性能表现[^3]。 --- ### 总结 针对 MyBatis 在 MySQL 下使用 `<foreach>` 导致 SQL 拼接过长的问题,建议优先评估业务需求合理性;必要时采用分批次写入、借助中间过渡对象或者重构原有设计思路等方式加以应对。同时注意定期监控线上环境运行状态以便及时发现类似瓶颈现象并采取相应措施予以缓解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值