处理系统中唯一约束的相关问题

老秦鸭 / 2024-12-19 / 原文

引言

今天在学SpringBoot时,新增用户时,用户表中id和username有Unique约束,是唯一的,但id是自增的,添加用户的时候也默认不填id。但用户名总要用户自己创建,那么问题来了。

是应该在得到要添加的用户名后先去查询一下数据库中是否存在该用户,如果存在就终止后面的步骤。还是不进行这步对比操作,等到抛出异常时再捕获并返回错误信息给前端?

预验证

在尝试插入数据之前,先查询数据库中是否存在相同的用户名。如果存在,就停止,终止后面的操作,并返回相应的Message给前端。

优点

  • 可以提前发现冲突,减少不必要的数据库操作。
  • 用户可以立即获得反馈,知道用户名是否可用。

缺点

  • 需要额外的查询操作,增加了系统的网络请求次数。
  • 在高并发环境下,可能存在竞态条件(race condition)。即在查询时用户名不存在,但在插入前被其他用户占用。

直接执行插入操作然后捕获异常

直接尝试插入数据,并在发生唯一键冲突时捕获异常,然后返回错误信息给前端。

优点

  • 减少了查询操作,简化了流程。
  • 无需担心竞态条件问题。

缺点

  • 插入操作可能会失败,增加了数据库的事务负担。
  • 用户可能需要等待一段时间才能收到反馈。

并发控制

乐观锁和悲观锁是并发控制的一种机制,用于多线程或多进程环境下对共享资源的访问管理,以防止数据不一致或竞态条件。它们的主要区别在于对待冲突的策略。

  • 悲观锁是一种对资源持有较悲观态度的锁定方式。它假设数据在并发访问时极有可能发生冲突,因此每次访问数据时都会先加锁,以确保其他线程不能访问此数据直到锁被释放。
  • 乐观锁则持相对乐观的态度,假设并发操作冲突的可能性较小,因此不会主动加锁,而是进行数据版本检查来决定是否提交操作。

总结

如果系统对实时性和用户体验有较高要求,建议先进行预验证。这样可以避免不必要的数据库操作,并及时反馈给用户。

如果系统不需要严格的实时性验证,并且希望简化后端逻辑,可以选择直接插入并捕获异常的方式。

但是一般来说,创建用户的操作对于系统而言是比较少的(没遇到攻击的情况下),进行预验证是首选的。

当然也可以结合预验证和乐观锁的优点,因为小孩子才做选择,我全都要!

鳌拜-我全都要