V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
ZiLong
V2EX  ›  问与答

防止插入重复,是用数据库的唯一性约束好还是先去数据库查询存不存在好?

  •  
  •   ZiLong · 2016-09-27 15:34:48 +08:00 · 5466 次点击
    这是一个创建于 2978 天前的主题,其中的信息可能已经有所发展或是发生改变。
    27 条回复    2016-09-28 17:11:50 +08:00
    benatsh
        1
    benatsh  
       2016-09-27 15:58:23 +08:00
    看你对系统的性能要求
    murmur
        2
    murmur  
       2016-09-27 15:59:46 +08:00
    两个都要做,如果是注册的话肯定要 ajax 查一次用户重复不重复,然后防止捏造数据约束也得处理
    xing393939
        3
    xing393939  
       2016-09-27 16:05:11 +08:00
    数据库约束一下又不会怀孕
    xss
        4
    xss  
       2016-09-27 16:14:42 +08:00   ❤️ 1
    唯一约束.

    你触发一次数据库查询.

    如果是先查询在插入至少要 4 次网络 IO, 还可能会产生磁盘 IO
    都是严重拖慢性能的东西.

    当然,如果你的业务也就几千条数据,那么无所谓了~你用着爽就行.
    ZiLong
        5
    ZiLong  
    OP
       2016-09-27 16:21:55 +08:00
    @benatsh 我是追求越高越好
    ZiLong
        6
    ZiLong  
    OP
       2016-09-27 16:23:44 +08:00
    @murmur 针对这个场景,我可不可以加唯一性约束,直接插入数据库,通过捕获抛出的异常来判定是重复的呢
    ZiLong
        7
    ZiLong  
    OP
       2016-09-27 16:25:12 +08:00
    @xss 明显是用唯一性约束爽噻,查数据库不写代码么
    tairan2006
        8
    tairan2006  
       2016-09-27 16:28:00 +08:00   ❤️ 1
    肯定是唯一约束啊,你先查再插,要考虑并发问题啊,再来一个分布式锁?
    xss
        9
    xss  
       2016-09-27 16:28:20 +08:00
    @ZiLong 一般如果我消重的逻辑如果是先查数据库,在判断是否重复的话,我会把查询封装成一个通用函数,然后通过参数来改变查询函数的逻辑功能.你如果用唯一约束,就直接插,外面用异常给包住就行了.
    vwhenx
        10
    vwhenx  
       2016-09-27 16:29:17 +08:00   ❤️ 1
    都要做
    先去数据库查询是为了用户体验
    据库的唯一性约束是为了保证数据一致性
    Ouyangan
        11
    Ouyangan  
       2016-09-27 16:35:39 +08:00
    @vwhenx 说的有道理
    ZiLong
        12
    ZiLong  
    OP
       2016-09-27 16:56:22 +08:00
    @tairan2006 谢谢,一针见血
    ZiLong
        13
    ZiLong  
    OP
       2016-09-27 17:00:34 +08:00
    @xss 我只是想比较两种方式的优缺点,具体怎么做,封不封装函数不关心
    ZiLong
        14
    ZiLong  
    OP
       2016-09-27 17:29:55 +08:00
    @vwhenx @Ouyangan 查数据库为了用户体验的话,相当于这个场景很类似上面人提到的 ajax,比如 ajax 单独查用户名是否重复.不知道你说是否是这样的场景?我的意思是所有的字段都比如密码,生日这些都来了,然后要进行入库操作了,是先查询好,还是直接插入由数据库约束. @tairan2006 同学也提到了查询的并发问题,我觉得这提的很好.
    Ouyangan
        15
    Ouyangan  
       2016-09-27 19:23:56 +08:00
    @ZiLong 并发的问题实际上对应的是:数据库事务隔离级别 , java 的话 spring 有相应支持 .其他语言不熟悉.
    akira
        16
    akira  
       2016-09-27 20:26:30 +08:00
    单纯的先查再插是不能保证数据唯一的
    约束是肯定要上的
    个人更倾向于使用队列来处理类似的事情,除非量级过大或过小
    ldbC5uTBj11yaeh5
        17
    ldbC5uTBj11yaeh5  
       2016-09-27 20:44:08 +08:00
    vwhenx
        18
    vwhenx  
       2016-09-27 22:12:36 +08:00
    @ZiLong 不一定非要用什么 ajax ,我自己用 ruby on rails, 可以在 Model 里面定义 validation ,在保存到数据库之前应该会自己去查一遍,如果重复,会给一个提示放在 session 里面返回回去。
    mingyun
        19
    mingyun  
       2016-09-27 22:47:36 +08:00
    唯一键, mysql 用 INSERT ... ON DUPLICATE KEY
    sherlocktheplant
        20
    sherlocktheplant  
       2016-09-27 23:05:00 +08:00
    用户名两样都要做
    其他地方 只做数据库 然后处理好异常就可以
    sherlocktheplant
        21
    sherlocktheplant  
       2016-09-27 23:05:42 +08:00
    还有 开发阶段优化性能都是鬼扯 你连实战时候瓶颈在哪都不知道 盲目优化就是过度设计
    wsy2220
        22
    wsy2220  
       2016-09-28 01:00:23 +08:00 via Android
    数据库不就是用来搞这个的么……
    lslqtz
        23
    lslqtz  
       2016-09-28 05:56:01 +08:00
    前端提醒用查询,伪造用约束。
    正常情况下不伪造如果不正确就只会有查询。
    ZiLong
        24
    ZiLong  
    OP
       2016-09-28 09:41:03 +08:00
    @Ouyangan 我觉得你概念搞错了,事务用于保证 ACID,但事务不是互斥的,无法解决并发问题.比如,我查询的时候本来是没有的,然后我查完了,应用程序在做其他事情(比如组装数据),此时其他线程向数据库中插入了一条数据,这条数据与我要插入数据相同,我插入的时候就重复了.这只是一种并发情况,很多种情况都会造成类似这样的并发问题,进而导致数据重复
    ZiLong
        25
    ZiLong  
    OP
       2016-09-28 09:44:13 +08:00
    @vwhenx 框架只是帮你简化工作,但是框架实现细节应该也会遇到类似问题
    Nagisa1992
        26
    Nagisa1992  
       2016-09-28 10:26:07 +08:00
    @mingyun 我这边需要获取 insert 和 update 的数量,是不是不能用 ON DUPLICATE KEY ,只能先 select 再 insert 或者 update 然后 count++?
    ZiLong
        27
    ZiLong  
    OP
       2016-09-28 17:11:50 +08:00
    @Nagisa1992 你这个后台不好区分是 update 还是 insert,你如果不加唯一性约束,有可能插入重复的,加了的话,你查询的时候数据库没有,但你插入的时候有可能数据库被其他线程插入了你要插入的数据,你不管直接不加就是了,你要管的话,就要判定抛出的是否是唯一性约束检验失败抛出的异常,进而执行 Update 才++.
    另外的方式是,让前端(APP)告诉你是 inset 还是 update,比如,更新和插入走不同接口或者加入一些辅助判断的字段.还有,可以写存储过程或函数,让返回值告诉你.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2915 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:10 · PVG 11:10 · LAX 19:10 · JFK 22:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.