生产环境常见数据与SQL相关问题解析
一、迭代器使用不当引发的并发修改异常
在处理集合过滤时,使用迭代器遍历并移除不符合条件的对象是常见操作。但若逻辑判断中存在多个独立的 remove() 调用,可能触发 ConcurrentModificationException。
原始代码如下:
if (board.getName() == null || board.getName().isEmpty()) {
iterator.remove();
}
if (board.getPbiCode() == null || board.getPbiCode().isEmpty()) {
iterator.remove();
}
问题在于:当一个对象同时满足两个条件时,iterator.remove() 被调用两次,而迭代器仅允许一次删除操作,导致运行时异常。
正确做法是使用 else if 避免重复删除:
if (board.getName() == null || board.getName().isEmpty()) {
iterator.remove();
} else if (board.getPbiCode() == null || board.getPbiCode().isEmpty()) {
iterator.remove();
}
此外,应始终检查输入数据的完整性,尤其是来自数据库的字段是否包含空值或非法值,避免因脏数据导致逻辑错误。
二、SQL查询设计中的实践误区
在排查数据缺失问题时,曾误以为必须使用子查询才能关联两张表,实际上通过 JOIN 可以高效完成多表联合查询。
例如,要确认某类数据是否存在缺失,可直接写:
SELECT t1.*, t2.status
FROM table_a t1
LEFT JOIN table_b t2 ON t1.id = t2.ref_id
WHERE t2.id IS NULL;
这能快速定位关联缺失的数据。同时,在复杂 WHERE 条件拼接时,应避免过度依赖字符串拼接,建议使用 MyBatis 动态 SQL 标签(如 <if>)提高可读性和安全性。
三、MyBatis 中布尔类型参数的陷阱
当传入的参数为基本类型 boolean 时,其默认值为 false,即使未显式赋值也会参与条件判断。
例如:
<select id="getFaultListPage" parameterType="com.domain.FaultQueryBean"
resultType="com.vo.FaultVo">
SELECT mf.SHE_ID sheId, mf.CODE, mfi.IMPLEMENT_PROCESS implementProcess
FROM mm_fault mf
WHERE mf.MARK_FOR_DELETE = 0
<if test="bean.isSyncQis != null">
AND mf.is_sync_qis = #{bean.isSyncQis}
</if>
ORDER BY mf.ID DESC
</select>
若 isSyncQis 是 boolean,则无论是否传参,都会被当作 false 处理,可能导致查询结果为空。推荐使用包装类型 Boolean,支持 null 值,从而实现更灵活的条件控制。
四、MySQL 的 ON UPDATE CURRENT_TIMESTAMP 使用隐患
在实体类中定义了时间字段,并配置了 ON UPDATE CURRENT_TIMESTAMP,但在更新对象时未主动设置该字段为 null 或新实例,会导致数据库时间未更新。
示例:
// 错误做法
entity.setUpdateTime(new Date()); // 未清空原值,可能被忽略
// 正确做法
entity.setUpdateTime(null); // 强制触发数据库自动更新
// 或者
entity.setUpdateTime(new Date()); // 显式更新,确保持久化
若不显式重置时间字段,某些持久层框架可能跳过该字段的更新,导致时间戳未同步。