首页 智能穿戴

Mybatis 主键配置不当:数据丢失的深坑与填坑指南

分类:智能穿戴
字数: (4593)
阅读: (2686)
内容摘要:Mybatis 主键配置不当:数据丢失的深坑与填坑指南,

最近在项目中遇到了一个非常隐蔽的 Bug,最终定位到是 Mybatis 主键配置不当导致的数据丢失。这个问题让我意识到,即使是使用了多年的框架,在细节上稍有疏忽,也可能造成严重的后果。希望通过这篇文章,分享我踩过的坑以及填坑的经验,避免大家重蹈覆辙。

问题场景重现:数据凭空消失

我们有一个用户订单表 user_order,其中 order_id 是主键,并且是自增的。在业务逻辑中,我们需要先插入订单信息,然后根据 order_id 进行后续的操作。当时使用的 Mybatis 配置如下(简化版):

<insert id="insertOrder" parameterType="UserOrder" useGeneratedKeys="true" keyProperty="orderId">
  INSERT INTO user_order (user_id, order_time) VALUES (#{userId}, #{orderTime})
</insert>

在测试环境一切正常,上线后却偶发性的出现数据丢失的情况:插入订单后,返回的 orderId 竟然是 null!导致后续的业务逻辑无法正常执行,相当于订单数据凭空消失了。

Mybatis 主键配置不当:数据丢失的深坑与填坑指南

底层原理深度剖析:MySQL 自增主键的特性

要理解这个问题,需要深入了解 MySQL 自增主键的特性以及 Mybatis 如何获取自增主键。

  1. MySQL 的 AUTO_INCREMENT:MySQL 的 AUTO_INCREMENT 机制保证了主键的唯一性和自增性。当插入数据时,如果没有指定主键的值,MySQL 会自动生成一个唯一的递增值。
  2. useGeneratedKeyskeyProperty:Mybatis 的 useGeneratedKeys 属性设置为 true 时,会指示 Mybatis 使用 JDBC 的 getGeneratedKeys() 方法来获取数据库自动生成的主键值。keyProperty 属性指定了将获取到的主键值设置到哪个 Java 对象的属性上。
  3. JDBC 的 getGeneratedKeys():JDBC 的 getGeneratedKeys() 方法返回一个 ResultSet 对象,其中包含了数据库自动生成的主键值。但是,这个方法的实现依赖于具体的数据库驱动。

问题的原因在于:

Mybatis 主键配置不当:数据丢失的深坑与填坑指南

在高并发场景下,如果 MySQL 的连接池配置不当,或者网络出现短暂的抖动,Mybatis 获取 ResultSet 的时候可能会失败,导致无法正确获取到 orderId,从而返回 null

LSI 实体词共现:

Mybatis 主键配置不当:数据丢失的深坑与填坑指南

在上述场景中,我们使用了 MySQL 作为数据库,并且面临着高并发的挑战。为了应对高并发,我们使用了连接池技术,例如 Druid 或者 HikariCP。同时,为了保证系统的稳定性,我们还使用了 Nginx 进行反向代理和负载均衡。在高并发情况下,需要密切关注 MySQL 的并发连接数,合理设置连接池的大小,并且监控 Nginx 的状态。

解决方案:配置调整与代码优化

针对上述问题,我们采取了以下解决方案:

Mybatis 主键配置不当:数据丢失的深坑与填坑指南
  1. 调整 Mybatis 配置:为了避免获取主键失败的情况,我们可以使用 <selectKey> 标签,在插入数据之前或者之后,通过执行一个查询语句来获取主键值。
<insert id="insertOrder" parameterType="UserOrder">
  <selectKey keyProperty="orderId" order="AFTER" resultType="java.lang.Long">
    SELECT LAST_INSERT_ID()
  </selectKey>
  INSERT INTO user_order (user_id, order_time) VALUES (#{userId}, #{orderTime})
</insert>
  • keyProperty:指定了将获取到的主键值设置到哪个 Java 对象的属性上。
  • order:指定了 <selectKey> 标签中的查询语句在 INSERT 语句之前还是之后执行。AFTER 表示在 INSERT 语句之后执行。
  • resultType:指定了查询结果的类型。
  1. 优化 MySQL 连接池配置:合理设置连接池的大小,避免连接耗尽。可以根据实际的并发量和数据库服务器的性能进行调整。
  2. 增加重试机制:在获取主键失败的情况下,可以增加重试机制,例如重试 3 次。但是需要注意,重试机制可能会增加系统的延迟,需要根据实际情况进行权衡。

实战避坑经验总结

  1. 仔细阅读 Mybatis 官方文档:Mybatis 官方文档包含了大量的细节信息,仔细阅读官方文档可以避免很多常见的错误。
  2. 充分的测试:在上线之前,进行充分的测试,包括单元测试、集成测试和压力测试。特别是要模拟高并发场景,检查是否存在数据丢失的情况。
  3. 监控和告警:建立完善的监控和告警机制,及时发现和解决问题。可以监控 MySQL 的连接数、QPS、慢查询等指标。
  4. 代码 Code Review:代码 Code Review 可以帮助发现潜在的问题,提高代码质量。
  5. 善用日志:打印详细的日志,方便问题排查。可以记录 SQL 语句、参数和执行结果。

通过这次踩坑经历,我深刻体会到,即使是使用了多年的框架,也需要保持学习和探索的精神,不断深入了解其原理和细节。只有这样,才能避免重蹈覆辙,写出更加健壮和可靠的代码。

Mybatis 主键配置不当:数据丢失的深坑与填坑指南

转载请注明出处: 键盘上的咸鱼

本文的链接地址: http://m.acea2.store/blog/034519.SHTML

本文最后 发布于2026-03-29 20:36:31,已经过了28天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 社恐患者 6 天前
    请问大佬,如果使用的是分布式 ID 生成器(如雪花算法),还需要考虑这些问题吗?
  • 欧皇附体 3 天前
    感谢分享!`<selectKey>` 标签确实是一个不错的解决方案,避免了在高并发下获取主键失败的情况。不过重试机制需要谨慎使用,防止死循环。
  • 向日葵的微笑 4 天前
    楼主讲的真透彻,解决了我的一个大问题!之前一直百思不得其解,原来是这里出了问题,感谢!
  • 单身狗 3 天前
    感谢分享!`<selectKey>` 标签确实是一个不错的解决方案,避免了在高并发下获取主键失败的情况。不过重试机制需要谨慎使用,防止死循环。