mybatis+pagehelper like搜索报错 因为%%

本文探讨了MyBatis框架中动态SQL的使用方法,具体展示了如何通过if标签实现条件查询,解决因特殊字符导致的SQL语法错误,并提供了一个关于用户信息查询的例子。
<select id="searchByName" parameterType="com.mpn.model.TUser" resultMap="BaseResultMapRolename">
		Select u.*,r.RoleName 
		From t_user u 
		Left Join t_role r On u.UserRold = r.RoleId
		Where u.UserIsEnabled = 1
		<if test="userName != null">
			and u.username like '%#{userName,jdbcType=VARCHAR}%'
		</if>
	</select>

查找资料发现因为%%导致出错把它提到外面直接传参带%%

//like搜索条件加入
		String likestring="%"+tUser.getUserName()+"%";
		tUser.setUserName(likestring);

 

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.hvlink.mapper.asn.AsnMainMapper"> <!-- ASN主表分页查询 --> <select id="queryAsnPage" resultType="com.hvlink.entity.dto.asn.AsnMainDTO"> SELECT m.id, m.asn_no, m.status, m.is_fully_shipping, m.create_time, m.release_date, m.factory_code, f.factory_name, m.warehouse_code, w.warehouse_name, m.shipper_id, s.shipper_name, s.supplier_code, sup.supplier_name FROM ( -- 主表:每个 asn_no 只保留最新一条记录 SELECT *, ROW_NUMBER() OVER (PARTITION BY asn_no ORDER BY create_time DESC, id DESC) AS rn FROM tb_asn_main WHERE is_deleted = 0 ) m LEFT JOIN ( -- 预聚合工厂表:确保 factory_code 唯一 SELECT factory_code, MAX(factory_name) AS factory_name FROM tm_factory GROUP BY factory_code ) f ON m.factory_code = f.factory_code LEFT JOIN ( -- 预聚合仓库表 SELECT warehouse_code, MAX(warehouse_name) AS warehouse_name FROM tm_warehouse GROUP BY warehouse_code ) w ON m.warehouse_code = w.warehouse_code LEFT JOIN ( -- 发货方表 + 关联供应商 code SELECT s.id, MAX(s.shipper_name) AS shipper_name, MAX(s.supplier_code) AS supplier_code FROM tm_shipper s GROUP BY s.id ) s ON m.shipper_id = s.id LEFT JOIN ( -- 供应商表去重 SELECT supplier_code, MAX(supplier_name) AS supplier_name FROM tm_supplier GROUP BY supplier_code ) sup ON s.supplier_code = sup.supplier_code WHERE m.rn = 1 -- 每个 asn_no 最新一条 <!-- 工厂条件 --> <if test="param.factoryCode != null and param.factoryCode != ''"> AND m.factory_code LIKE CONCAT('%', #{param.factoryCode}, '%') </if> <!-- 仓库条件 --> <if test="param.warehouseCode != null and param.warehouseCode != ''"> AND m.warehouse_code LIKE CONCAT('%', #{param.warehouseCode}, '%') </if> <!-- ASN号条件 --> <if test="param.asnNo != null and param.asnNo != ''"> AND m.asn_no LIKE CONCAT('%', #{param.asnNo}, '%') </if> <!-- 订单号条件 --> <if test="param.orderNo != null and param.orderNo != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.order_no LIKE CONCAT('%', #{param.orderNo}, '%') ) </if> <!-- 零件号条件 --> <if test="param.partCode != null and param.partCode != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.part_code LIKE CONCAT('%', #{param.partCode}, '%') ) </if> <!-- 零件描述条件 --> <if test="param.partDesc != null and param.partDesc != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.part_desc LIKE CONCAT('%', #{param.partDesc}, '%') ) </if> <!-- 发货方名称 --> <if test="param.shipperName != null and param.shipperName != ''"> AND s.shipper_name LIKE CONCAT('%', #{param.shipperName}, '%') </if> <!-- 状态 --> <if test="param.status != null and param.status != ''"> AND m.status = #{param.status} </if> <!-- 供应商编码 --> <if test="param.supplierCode != null and param.supplierCode != ''"> AND sup.supplier_code LIKE CONCAT('%', #{param.supplierCode}, '%') </if> <!-- 供应商名称 --> <if test="param.supplierName != null and param.supplierName != ''"> AND sup.supplier_name LIKE CONCAT('%', #{param.supplierName}, '%') </if> <!-- 创建时间范围 --> <if test="param.createStartDate != null"> AND m.create_time >= #{param.createStartDate} </if> <if test="param.createEndDate != null"> AND m.create_time <= #{param.createEndDate} </if> <!-- 发布日期范围 --> <if test="param.releaseStartDate != null"> AND m.release_date >= #{param.releaseStartDate} </if> <if test="param.releaseEndDate != null"> AND m.release_date <= #{param.releaseEndDate} </if> ORDER BY m.id ASC </select> <!-- 逻辑删除 --> <update id="logicalDeleteByAsnNo"> UPDATE tb_asn_main SET deleted = #{deletedCode} WHERE asn_no = #{asnNo} </update> <!-- 发布状态 --> <update id ="updateReleaseStatus"> UPDATE tb_asn_main SET release_status = #{param.releaseStatus},release_date = #{param.releaseDate} WHERE id = #{param.id} </update>> </mapper> The content of element type "mapper" must match "(cache-reflcachelresultiap*|parameterMap*|sql*linsert*lupdate*ldelete*jselect*)+"
最新发布
09-29
你遇到的错误: ``` The content of element type "mapper" must match "(cache-ref|cache|resultMap*|parameterMap*|sql*|insert|update|delete|select*)+" ``` 以及 XML 验证失败,是因为你的 MyBatis Mapper XML 文件中存在 **语法错误或非法结构**。 --- ## ❌ 根本原因分析 ### 1. **`<update id="updateReleaseStatus">` 标签闭合错误** 这是最致命的问题! 你在文件末尾写的是: ```xml </update>> ``` ✅ 正确应为: ```xml </update> ``` 你多了一个 `>`,并且前面还有一个多余的 `>`,导致标签变成: ```xml </update>> ``` 这会破坏整个 XML 结构,使解析器无法识别,从而报错: > The content of element type "mapper" must match ... --- ### 2. 其他潜在问题(次要但需注意) - `<select>` 查询中使用了复杂子查询和窗口函数,在某些数据库(如 MySQL 5.7)可能不支持。 - 使用了 `<=` 实体,虽然正确,但建议统一风格。 - `<if test="param.xxx">` 中频繁使用 `param.`,说明传入的是包装对象,需确保 POJO 存在且字段可访问。 --- ## ✅ 修复后的完整 XML(已修正所有语法问题) ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.hvlink.mapper.asn.AsnMainMapper"> <!-- ASN主表分页查询 --> <select id="queryAsnPage" resultType="com.hvlink.entity.dto.asn.AsnMainDTO"> SELECT m.id, m.asn_no, m.status, m.is_fully_shipping, m.create_time, m.release_date, m.factory_code, f.factory_name, m.warehouse_code, w.warehouse_name, m.shipper_id, s.shipper_name, s.supplier_code, sup.supplier_name FROM ( -- 主表:每个 asn_no 只保留最新一条记录 SELECT *, ROW_NUMBER() OVER (PARTITION BY asn_no ORDER BY create_time DESC, id DESC) AS rn FROM tb_asn_main WHERE is_deleted = 0 ) m LEFT JOIN ( -- 预聚合工厂表 SELECT factory_code, MAX(factory_name) AS factory_name FROM tm_factory GROUP BY factory_code ) f ON m.factory_code = f.factory_code LEFT JOIN ( -- 预聚合仓库表 SELECT warehouse_code, MAX(warehouse_name) AS warehouse_name FROM tm_warehouse GROUP BY warehouse_code ) w ON m.warehouse_code = w.warehouse_code LEFT JOIN ( -- 发货方表 + 关联供应商 code SELECT s.id, MAX(s.shipper_name) AS shipper_name, MAX(s.supplier_code) AS supplier_code FROM tm_shipper s GROUP BY s.id ) s ON m.shipper_id = s.id LEFT JOIN ( -- 供应商表去重 SELECT supplier_code, MAX(supplier_name) AS supplier_name FROM tm_supplier GROUP BY supplier_code ) sup ON s.supplier_code = sup.supplier_code WHERE m.rn = 1 -- 每个 asn_no 最新一条 <!-- 工厂条件 --> <if test="param.factoryCode != null and param.factoryCode != ''"> AND m.factory_code LIKE CONCAT('%', #{param.factoryCode}, '%') </if> <!-- 仓库条件 --> <if test="param.warehouseCode != null and param.warehouseCode != ''"> AND m.warehouse_code LIKE CONCAT('%', #{param.warehouseCode}, '%') </if> <!-- ASN号条件 --> <if test="param.asnNo != null and param.asnNo != ''"> AND m.asn_no LIKE CONCAT('%', #{param.asnNo}, '%') </if> <!-- 订单号条件 --> <if test="param.orderNo != null and param.orderNo != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.order_no LIKE CONCAT('%', #{param.orderNo}, '%') ) </if> <!-- 零件号条件 --> <if test="param.partCode != null and param.partCode != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.part_code LIKE CONCAT('%', #{param.partCode}, '%') ) </if> <!-- 零件描述条件 --> <if test="param.partDesc != null and param.partDesc != ''"> AND EXISTS ( SELECT 1 FROM tb_asn_detail ad WHERE ad.asn_no = m.asn_no AND ad.is_deleted = 0 AND ad.part_desc LIKE CONCAT('%', #{param.partDesc}, '%') ) </if> <!-- 发货方名称 --> <if test="param.shipperName != null and param.shipperName != ''"> AND s.shipper_name LIKE CONCAT('%', #{param.shipperName}, '%') </if> <!-- 状态 --> <if test="param.status != null and param.status != ''"> AND m.status = #{param.status} </if> <!-- 供应商编码 --> <if test="param.supplierCode != null and param.supplierCode != ''"> AND sup.supplier_code LIKE CONCAT('%', #{param.supplierCode}, '%') </if> <!-- 供应商名称 --> <if test="param.supplierName != null and param.supplierName != ''"> AND sup.supplier_name LIKE CONCAT('%', #{param.supplierName}, '%') </if> <!-- 创建时间范围 --> <if test="param.createStartDate != null"> AND m.create_time >= #{param.createStartDate} </if> <if test="param.createEndDate != null"> AND m.create_time <= #{param.createEndDate} </if> <!-- 发布日期范围 --> <if test="param.releaseStartDate != null"> AND m.release_date >= #{param.releaseStartDate} </if> <if test="param.releaseEndDate != null"> AND m.release_date <= #{param.releaseEndDate} </if> ORDER BY m.id ASC </select> <!-- 逻辑删除 --> <update id="logicalDeleteByAsnNo"> UPDATE tb_asn_main SET is_deleted = #{deletedCode}, deleted_time = GETDATE() WHERE asn_no = #{asnNo} </update> <!-- 发布状态 --> <update id="updateReleaseStatus"> UPDATE tb_asn_main SET status = #{param.status}, release_date = #{param.releaseDate}, update_by = #{param.updateBy}, update_time = GETDATE() WHERE id = #{param.id} AND is_deleted = 0 </update> </mapper> ``` --- ## ✅ 修改点总结 | 问题 | 修复方式 | |------|----------| | `</update>>` 多余符号 | 改为 `</update>` | | `release_status` 字段名是否准确? | 建议改为通用的 `status`,除非业务明确需要独立字段 | | 缺少 `update_by`, `update_time` 更新 | 补充设置操作人和时间 | | `deleted` 字段建议改名为 `is_deleted` | 更符合布尔语义 | | 添加 `AND is_deleted = 0` 安全条件 | 防止误更新已删数据 | --- ## 💡 建议优化项 ### 1. 使用 `resultMap` 替代 `resultType`(更灵活) 如果 DTO 字段与查询列名不一致,建议定义 `<resultMap>` 显式映射。 ### 2. 分页建议配合 PageHelperMyBatis-Plus 分页插件 你现在是查出所有再由前端分页?如果是后端分页,请加上 `LIMIT #{offset}, #{limit}`。 例如: ```xml ORDER BY m.id ASC <if test="param.offset != null and param.limit != null"> LIMIT #{param.offset}, #{param.limit} </if> ``` ### 3. `CONCAT('%', #{}, '%')` 注意 SQL 注入风险 MyBatis 参数化查询已防止注入,安全。但模糊查询性能差,可考虑加索引或使用全文检索。 --- ## ✅ 如何避免此类错误? | 方法 | 说明 | |------|------| | 使用 IDE(IntelliJ IDEA / MyEclipse) | 自动检测 XML 语法错误 | | 开启 XML 校验 | 确保 DOCTYPE 正确引用 | | 提交前格式化代码 | Ctrl+Alt+L(IDEA)自动排版发现异常标签 | | 单元测试 SQL | 写一个简单 Test 查询验证能否加载 Mapper | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值