V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
ZiLong
V2EX  ›  问与答

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

  •  
  •   ZiLong · Sep 27, 2016 · 5954 views
    This topic created in 3507 days ago, the information mentioned may be changed or developed.
    27 replies    2016-09-28 17:11:50 +08:00
    benatsh
        1
    benatsh  
       Sep 27, 2016
    看你对系统的性能要求
    murmur
        2
    murmur  
       Sep 27, 2016
    两个都要做,如果是注册的话肯定要 ajax 查一次用户重复不重复,然后防止捏造数据约束也得处理
    xing393939
        3
    xing393939  
       Sep 27, 2016
    数据库约束一下又不会怀孕
    xss
        4
    xss  
       Sep 27, 2016   ❤️ 1
    唯一约束.

    你触发一次数据库查询.

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

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