当前位置: 首页 > 知识库问答 >
问题:

springboot - 为什么用户名重复时数据库自增主键没有回滚到预期状态?

束向荣
2025-03-25

我写了一个注册用户的接口和处理用户名相同的异常,当抛出这个异常的时候做事务回滚,现在我使用postman对我这个接口测试的时候,正常注册并插入数据库没有问题,但是当用户名相同的时候,id(自增主键)并没有像我学习的回滚那样1->3,而是1->2,我打开日志也显示是已经回滚,我现在不知道为什么会出现这样的情况

我认为当事务回滚的时候,自增主键id是不连续的状态而不是连续的

共有1个答案

韦宣
2025-03-25

自增主键(AUTO_INCREMENT)的递增机制与事务回滚的关系需要从数据库底层机制来理解:

  1. 自增主键的分配机制
    自增主键的递增发生在插入操作时,而不是事务提交时。当执行INSERT语句时:
  2. 数据库会立即预分配下一个自增ID
  3. 这个分配操作本身是事务无关的
  4. 即使事务回滚,已分配的自增值也不会被回收
  5. 事务回滚的作用范围
    事务回滚可以保证:
    ✓ 已插入的数据行会被删除
    ✓ 表锁/行锁会被释放
    ✓ 但不会回滚以下内容:

    • 自增计数器的当前值
    • 已分配的序列号(如Oracle的sequence)
    • 某些数据库的缓存预分配机制
  6. 不同数据库的具体表现
  7. MySQL InnoDB:自增值永久递增(内存中维护计数器)
  8. PostgreSQL:使用序列(SEQUENCE),默认也不会回退
  9. SQL Server:类似行为,自增值不连续
  10. **验证实验(以MySQL为例):

    START TRANSACTION;
    INSERT INTO users (username) VALUES ('test'); -- 分配id=2
    ROLLBACK; 
    INSERT INTO users (username) VALUES ('test'); -- 实际得到id=3
  11. 解决方案建议
    如果需要连续ID:
  12. 不要依赖自增主键的连续性(不符合数据库设计原则)
  13. 改用程序生成的UUID或其他分布式ID方案
  14. 定期使用ALTER TABLE重置自增值(不推荐,存在并发风险)
  15. 业务层应对
  16. 主键应该仅作为唯一标识符,不承载业务逻辑
  17. 需要连续编号时应单独建立业务流水号字段
  18. 通过定期维护任务清理不连续的空隙(如果有必要)

这是数据库的标准设计行为,目的是保证主键分配的原子性和高性能。自增主键的连续性不是事务的保证范围,而是需要根据具体业务需求选择合适的主键生成策略。

 类似资料:
  • 问题内容: 我想在ala SQL Server列中实现标识或自动递增值: 如何才能做到这一点? 问题答案: 正如Orbman所说,实现此目标的标准方法是使用序列。大多数人也将其与插入触发器结合在一起。因此,当插入没有ID的行时,触发器将触发以从序列中为您填写ID。 这是在Oracle中使用触发器的少数情况之一。

  • 为什么我的值不能进入数据库? 如果需要更多的代码,请告诉我。 警告: 查询连接中的异常。php第713行:SQLSTATE[23000]:完整性约束冲突:1048列“name”不能为空(SQL:insert-into(,,,,)值(,,2016-06-19 21:44:05,2016-06-19 21:44:05)) 控制器: HTML页面:

  • 我在Talend创建了一个作业,其中我必须生成包含用tRowGenerator生成的数据的文件,以及其他源:SQL Server数据库和分隔文件。 问题是我有相同主键的重复文件。我只想获得100条记录(420行):对于每个随机生成的UUID,我将获得42行,以此类推,但相反,我将获得相同的行10次(它重复了10次)

  • 问题内容: 我试图找出“最佳做法”,以确定是否要添加自动递增的整数作为表的主键。 假设我有一个表格,其中包含有关化学元素的数据。每个元素的原子序数是唯一的,并且永远不会改变。因此,与其对每列使用一个自动递增的整数,不如仅使用原子序数会更有意义,对吗? 如果我有一本书,那会是真的吗?我应该使用ISBN还是自动递增的整数作为主键?还是包含每个人的SSN的员工表? 问题答案: 关于Stack Overf

  • 我在Postgres中有两个表<code>foo 当我尝试使用此命令将数据从 复制到 时: 我得到一个错误: 错误:重复的键值违反了唯一约束“bar_pkey” 详细信息:键(id)=(1)已存在。 当表

  • 问题内容: 我编写了一个Java程序来访问MySQL innodb数据库。 每当INSERT IGNORE语句遇到重复的条目时,“自动增量”主键就会递增。 这是预期的行为吗?我认为IGNORE不应该发生这种情况。这意味着,IGNORE实际上会产生写入新主键值的额外开销。 下表如下: 谢谢! 问题答案: 从MySQL 5.1.22开始,这就是默认行为。 如果您想避免自动增量列中出现空白,可以将配置变

  • 我有两个表,其中主键(另一个表上的外键)在运行时自动递增(使用TOAD for mysql)。如何使用事务将数据同时插入两个表中。 这是第一个表的ddl: 第二个表的ddl: 注意:主要的挑战是从主键上获取自动递增的键值,以便在运行时插入到另一个表中。 提前谢谢。

  • 问题内容: 是否可以在不将SQL Server主列作为主键的情况下自动对其进行递增? 如果是,该怎么做。 谢谢 问题答案: 是的。不需要将列设为主键。 虽然我不确定这何时会有用。如果您有一个要用作PK的自然键,那么您可能还是想对代理替代键施加一个唯一约束。 出于建立FK关系的目的,SQL Server不在乎该列是否为PK,它只需要在其上具有唯一索引即可。