从“内存操作”到“原子更新”:一次代码思维的跃迁

发布于:2025-09-04 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、引言:我们是如何“习惯性”写代码的?

在日常开发中,我们常常会遇到这样的需求:

“用户每操作一次,计数器 +1,同时向一个列表中添加一条记录。”

于是,很多开发者(包括曾经的我)会本能地写出如下代码:

// 原始代码:典型的“内存操作”思维
Integer turnQualityNum = session.getTurnQualityNum();
JSONArray qualityCode = session.getQualityCode();

// 自增逻辑在 Java 层
if (turnQualityNum == null) {
    turnQualityNum = 0;
} else {
    turnQualityNum++;
}

// 集合操作在 Java 层
if (qualityCode == null) {
    qualityCode = new JSONArray();
}
qualityCode.add(issueVO.getIssueQualityCode());

// 回写并更新
session.setTurnQualityNum(turnQualityNum);
session.setQualityCode(qualityCode);
sessionService.updateById(session);

这段代码逻辑清晰、易于理解,在单线程环境下完全没问题。但一旦进入生产环境,面对高并发请求,问题就暴露了:

  • 并发安全问题:多个请求同时读取 turnQualityNum,都执行 ++,导致自增丢失;
  • JSON 操作风险JSONArray 是内存对象,修改后需序列化回 JSON 字符串,容易出错;
  • 非原子性:读 → 改 → 写,三步操作中间可能被其他线程打断。

二、问题的本质:我们把数据库当成了“只读存储”

上述代码的思维模式是典型的 “内存中心主义”

  1. 从数据库“拿数据”;
  2. 在内存中“加工数据”;
  3. 把结果“写回去”。

这就像:

“我去银行取钱 → 在家里数钱 → 再存回去”
而不是直接在银行柜台说:
“请帮我账户余额 +100 元。”

数据库不仅仅是数据的“仓库”,它更是具备强大计算能力的“服务端”


三、思维转变:把“计算”交给数据库

真正的高并发、高可靠系统,应该让数据库自己完成“读-改-写”这一原子操作。我们只需要告诉它:“请对这条记录做这些变更”。

于是,我们写出优化后的 SQL:

UPDATE itsm_helpdesk_session
SET 
    -- 原子自增:null 则视为 0
    turn_quality_num = IFNULL(turn_quality_num, 0) + 1,
    
    -- JSON 原子操作:空则创建,有则追加
    quality_code = 
        CASE 
            WHEN #{issueQualityCode} IS NULL OR TRIM(#{issueQualityCode}) = '' THEN 
                quality_code  -- 空值则不更新
            WHEN quality_code IS NULL THEN 
                JSON_ARRAY(#{issueQualityCode})  -- null 则创建新数组
            ELSE 
                JSON_ARRAY_APPEND(quality_code, '$', #{issueQualityCode})  -- 追加
        END,
        
    update_time = NOW()  -- 自动更新时间
    
WHERE id = #{sessionId} AND is_deleted = 0;

✅ 优化后的优势:

对比项 原始代码 优化后代码
并发安全 ❌ 不安全,自增丢失 ✅ 原子操作,绝对安全
执行效率 ❌ 2次 SQL(查 + 更新) ✅ 1次 SQL,性能更高
数据一致性 ❌ 可能因异常导致中间状态 ✅ 要么成功,要么失败
代码复杂度 ❌ Java 层逻辑复杂 ✅ 逻辑集中在 SQL,简洁清晰
可维护性 ❌ 修改逻辑需改 Java 代码 ✅ 只需调整 SQL

四、核心思维转变:从“操作数据”到“声明意图”

旧思维(内存操作) 新思维(数据库原子更新)
“我先查出来,再改,再保存” “我告诉数据库我要什么结果”
依赖 Java 对象和集合 依赖数据库函数(IFNULLJSON_ARRAY_APPEND
容易忽略并发问题 天然避免并发问题
适合单机、低并发 适合高并发、分布式场景

🔑 关键认知升级
数据库不是“哑”存储,而是“智能”计算节点。


五、适用场景

这种思维特别适用于:

  • 计数器类字段(view_countlike_countturn_quality_num
  • JSON 数组的增删改(标签、操作记录、附件列表)
  • 状态流转(状态 + 时间 更新)
  • 任何“读 → 改 → 写”模式的操作

六、注意事项

  1. SQL 注入风险:使用 #{} 参数占位符,避免 ${} 拼接;
  2. JSON 函数支持:确保 MySQL ≥ 5.7;
  3. 空值处理:在 SQL 中显式处理 NULL 和空字符串;
  4. 事务控制:必要时仍需加事务,保证多表一致性。

七、结语:做一名“数据库友好”的开发者

从“内存操作”到“数据库原子更新”,不仅仅是代码的优化,更是一种 工程思维的跃迁

我们应当:

  • ✅ 信任数据库的能力
  • ✅ 减少不必要的内存计算
  • ✅ 让每一次更新都成为原子操作

下次当你写“先查后改”代码时,不妨问自己一句:

“这个操作,能不能让数据库自己完成?”

如果答案是“能”,那就大胆地把计算交给它吧!


文末互动:你在项目中还遇到过哪些“本该由数据库完成”的操作却被放在 Java 层处理的案例?欢迎在评论区分享!


网站公告

今日签到

点亮在社区的每一天
去签到