likes
comments
collection
share

唯一键校验应该使用数据库校验,还是先查询?

作者站长头像
站长
· 阅读数 21

引言

在Java里面:万物皆对象。在实际生活中:我们都是唯一的,我们都是某某某最重要的,我们也有自己最重要的某某某。在技术的世界里面,唯一也是我们经常会遇到的,但是总有人会纠结某一个点,希望这篇文章能够帮助大家解开这个纠结点。

一、数据库层面的唯一键约束

1.1 定义和作用

唯一键约束是数据库表中的一种规则,它强制要求在指定的列或列组合中,每一行的数据必须是唯一的,不允许重复。这种约束的作用是确保数据的准确性和唯一性,防止数据冗余和错误,同时支持数据的快速检索和索引优化。

1.2 优势

  • 自动性:数据库管理系统会自动执行唯一性检查,无需额外的应用程序逻辑。

  • 透明性:对应用程序和用户透明,所有通过数据库接口的操作都会受到唯一性约束的保护。

  • 数据一致性保障:确保了数据在数据库层面的一致性和可靠性,降低数据错误的风险。

1.3 局限性

  • 灵活性不足:数据库层面的唯一键约束可能不够灵活,难以适应复杂的业务规则或条件。

  • 可能的性能影响:在高并发或大数据量的情况下,唯一性检查可能会成为性能瓶颈,尤其是在没有适当索引支持的情况下。

1.4 数据库层面的约束代码是怎么写的

首先忽略数据库唯一键的创建,咱直接看代码层面如何处理,如下:

/**
 * 抽离异常监听公共参数
 *
 * @param processor 内部类
 * @return 操作结果
 */
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
protected Response saveOrUpdate(Processor processor, String message) throws Exception {
    try {
        // 执行具体的操作代码
        processor.execute();
        // 没有出错表示成功了
        return Response.buildSuccess("success");
    } catch (Exception e) {
        if (e instanceof MySQLIntegrityConstraintViolationException || e instanceof DuplicateKeyException) {
            // 唯一键冲突
            if (e.getLocalizedMessage().contains(getUkName().getName())) {
                throw new CustomException(null != message ? message : getUkName().getDesc() + "已存在");
            }
        }
        LOGGER.error(e.getLocalizedMessage(), e);
        // 错误采集到千里眼
        ExceptionCollActionEvent event = new ExceptionCollActionEvent(this.getClass(), e);
        SpringContextHolder.publishEvent(event);
        throw e;
    }
}

注意:上面是抽取的一个公共的数据库交互层,我们可以看到我们监听了异常;当数据库层面出现唯一异常的时候,我们可以在代码里面直接判断是否是我们要的唯一异常,是的话直接可以返回响应的错误消息给到用户端。

二、应用程序层面的查询校验

应用程序层面的查询校验是指在应用程序中实现对数据唯一性的检查,而不是依赖数据库层面的唯一键约束。以下是对这一概念的详细描述:

2.1 定义和实现方法

应用程序层面的查询校验通常在数据写入数据库之前进行。实现方法包括:

唯一键校验应该使用数据库校验,还是先查询?

  • 预检查询:在插入或更新数据之前,应用程序会执行一个查询,检查数据库中是否已存在具有相同唯一属性的记录。

  • 事务管理:确保查询和随后的数据操作在一个事务中执行,以保持数据的一致性。

  • 错误处理:如果查询发现重复记录,应用程序需要决定如何处理这种情况,比如提示用户、回滚事务或执行其他业务逻辑。

2.2 应用程序层面校验的优势和挑战

唯一键校验应该使用数据库校验,还是先查询?

  • 优势

    • 灵活性高:应用程序可以定义复杂的业务规则,对数据的唯一性进行更细致的控制,不仅限于数据库表结构所定义的约束。

    • 结合复杂业务逻辑:可以根据业务需求,结合其他业务逻辑进行数据校验,例如,只在特定条件下检查数据的唯一性。

  • 挑战

    • 实现复杂性:需要在应用程序中编写额外的代码来执行查询和逻辑判断,这可能会增加应用程序的复杂性。

    • 数据一致性依赖于应用程序的健壮性:如果应用程序在查询校验中存在缺陷或未能妥善处理异常情况,可能会导致数据不一致的问题。

三、两种方法的比较分析

特性数据库层面的唯一键约束应用程序层面的查询校验
强制性是,数据库自动强制执行唯一性检查否,需要应用程序逻辑来实现校验
保证数据一致性是,确保所有数据操作都满足唯一性约束否,依赖于应用程序逻辑的正确实现
减轻应用程序负担是,数据库负责唯一性检查,应用程序无需重复检查否,应用程序需要实现额外的查询和逻辑判断
灵活性否,可能在多条件唯一性校验时不够灵活是,可以根据具体业务需求进行定制
复杂性较低,数据库层面的实现简单明了较高,需要在应用程序中编写额外的代码来执行查询
实现风险较低,除非数据库层面出现问题较高,如果应用程序实现不当可能导致数据不一致

四、干货:解决方案和最佳实践

  • 双重校验:在应用程序层面进行查询校验的同时,也使用数据库层面的唯一键约束,以提供双重保障。

  • 优化查询性能:确保应用程序层面的查询尽可能高效,以避免对性能产生负面影响。

  • 编写健壮的代码:确保应用程序能够妥善处理所有可能的情况,包括查询失败、重复数据等情况。

  • 使用事务:确保数据操作的原子性,要么全部成功,要么全部失败,以维护数据一致性。

下面是我们实际编码合理的实现方案

controllerservicedaoalt[数据库唯一冲突]alt[用户存在][用户不存在]添加用户查询用户是否存在返回提示信息保存用户(这里可能别的用户注册了同名的)监听唯一冲突返回友好提示controllerservicedao

五、总结

啥叫正确?正确是由解决的问题决定的。问题不同,解决方案不同。我们不能忽略问题的本质。

虽然我上面写了个合理的实现方案,但是这个方案并不是处处使用都是合理的【但肯定是处处都可以使用的(^▽^)】

程序员对于我们的代码应该保持一个良好的审视之心,敬畏之心;千万不要以为一个技术方案拿来随便用就行,得结合实际业务去思考。

希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。

同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。

感谢您的支持和理解!

转载自:https://juejin.cn/post/7392249407221874729
评论
请登录