首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
V2EX  ›  MySQL

mysql 怎么防止重复插入呢

  •  
  •   noble4cc · 34 天前 · 4962 次点击
    这是一个创建于 34 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 unique key 可以保证

    但是不使用唯一 key 的情况并且在并发提交的情况下怎么防止重复插入呢?

    比如浏览器卡了一下,导致用户重复点击提交了

    47 回复  |  直到 2019-05-23 17:05:54 +08:00
        1
    JacFrak   34 天前
    如果是 ajax 提交,点击提交按钮事件里面将按钮设置为不可操作
        2
    noble4cc   34 天前
    @JacFrak 嗯嗯如果是单纯的 form 呢
        3
    DovaKeen   34 天前
    引入事务,在插入前先搜索一下有没有重复,如果有的话就取消插入,没有再插入?但是这样的话似乎要把隔离级别设置的很高…
        4
    DovaKeen   34 天前
    @noble4cc
    @JacFrak 我觉得虽然是 web 工程,但是浏览器并不一定是唯一的客户端,不能排除有潜在的攻击者自己构建 http 请求往服务器发的可能啊
        5
    zhuzhiqiang   34 天前
    form 埋个 token form 提交后就把这个 token 删了 token 不存在即是重复提交
        6
    peyppicp   34 天前
    分布式锁
        7
    hlwjia   34 天前 via iPhone
    没有 unique 的情况下只能先查重再插了
        8
    Immortal   34 天前
    服务端搞个 token 存到 session 或者什么地方 然后发给前端
    前端提交表单的时候一起提交着个 token
    如果一致就处理
    不一致当成重复提交 不处理
    以上是一个成熟且常规的做法
        9
    noble4cc   34 天前   ♥ 1
    @DovaKeen 好像是可以解决并发问题,查的时候加锁能解决
        10
    eluotao   34 天前
    插入或忽略
    如果我们希望插入一条新记录( INSERT ),但如果记录已经存在,就啥事也不干直接忽略,此时,
    可以使用 INSERT IGNORE INTO ...语句:

    INSERT IGNORE INTO students (id, class_id, name, gender, score) VALUES (1, 1, '小明', 'F', 99);
        11
    jorneyr   34 天前
    根据业务数据特点建立唯一索引
        12
    aitaii   34 天前 via iPhone   ♥ 2
    幂等
        13
    fl0w   34 天前
    insert into table(field1,field2)
    select value1,value2 from dual where not exists( select 1 from table where field1 = value1 and field2 = value2)
        14
    JacFrak   34 天前
    @Immortal 这个不错,受教
        15
    vance   34 天前
    分布式锁,单个数据库个可以 insert into XX ... select x from dual where not exists( select from xx )
        16
    noble4cc   34 天前
    @fl0w 不加锁查恐怕不行吧,会有幻读问题
        17
    noble4cc   34 天前
    @eluotao ignore 必须唯一 key
        18
    noble4cc   34 天前
    @Immortal 相当于这个 form 是一次性的也可以的
        19
    tabris17   34 天前
    一次性 token
        20
    Hellert   34 天前
    难道不应该是在每次提交前手动检查业务键是否重复吗?比如一些 编号 字段。
        21
    eziooooo   34 天前
    1. 请求锁(这个请求这个人 N 秒内只能请求一次)
    2. 事务
        22
    xuanbg   34 天前
    先查后写是需要加锁作为前提的,没有锁,就有幻读的可能。如果是分布式系统,那这个锁就必须是分布式锁才行。
    前端防重发是标准配置,不做的都不是合格的前端。
        23
    dilu   34 天前
    前端防连点,后端做个锁,记得开事务,表上加个唯一索引
        24
    est   34 天前
    1. 楼主问的是表单提交如何防止重复,这个其实很简单。用 E-tag 这个 http 头控制即可。根本 不用太涉及 db 层面的东西。在 session 就处理了。
    2. 如果是 db 层面需要防止重复,我个人遇到更麻烦的问题是批量插入的时候。没有主键和 uniq key 可以用来鉴别。很麻烦。
        25
    jowan   34 天前
    CSRF_TOKEN 可以解决这个问题,顺便还能解决跨站的表单提交
        26
    Weixiao0725   34 天前
    只有 uniq key 一条路子要想真正有效。
        27
    sun1991   34 天前
    从数据库层面上, 用 unique key 解决此类问题是最合适的, 为什么要给自己找不痛快呢?
        28
    glfpes   34 天前 via Android
    为何不能设置 unique ?
        29
    AngryPanda   34 天前   ♥ 1
    @jowan CSRF Token 并不是(也不能)用来解决这个问题的;

    最大的问题是,CSRF Token 并不会一直变化。
        30
    fmumu   34 天前
    先查重再插入,并发时候有重复插入的可能
    应该先插入再查重(使用隔离级别 read commit)吧
        31
    Comdex   34 天前 via Android
    使用队列使并发请求串行
        32
    jason19659   34 天前
    前端是用户表单的重复提交还是什么?无意的还是故意的?
    浏览器卡一下。。每次刷新生成一个 id 就完了,提交了这个 id 就不再处理
        33
    R18   34 天前 via Android
    悲观锁
        34
    pudgedoor   34 天前 via Android
    数据库锁怎么样,乐观锁
        35
    opengps   34 天前
    如果是浏览器卡了一下多点击了提交,那么先查询在写入可以应对
        36
    BestSera   34 天前
    for update
    悲观锁 乐观锁都行
        37
    799635347   34 天前
    分布式锁,或者丢消息队列串行消费,或者数据库级别加 unique 约束,token 这种应该不能解决
        38
    mikicomo   34 天前
    @eluotao #10 这也是要唯一键的,他 ignore 是一直监听着唯一键,如果抛出重复键错误直接忽略
        39
    luwies   34 天前
    貌似有一种办法是刷出这个提交信息的页面的时候给前端一个唯一值,提交信息的时候把找个值带上,如果是重复的就忽略了。
        40
    kiddult   34 天前
    @AngryPanda 他想的是在每次提交前的页面访问都重新生成 CSRF Token,解除和 session 的绑定
        41
    momocraft   34 天前
    实施难度和风险和效果看 unique key 还不错?
        42
    loveCoding   34 天前
    数据库层 唯一约束
    应用层 分布式锁
        43
    arthas2234   34 天前
    重复提交这个事,不应该用 unique key 来防御,建议使用 token
        44
    rockyou12   34 天前   ♥ 1
    纯 rest,直接请求里带一个 requestId,由前端生成的 uuid。如果表(或者放 redis 或直接后端缓存下)已经出现,就直接拒绝
        45
    seanpan   34 天前 via iPhone
    表单令牌
        46
    lusi1990   33 天前 via Android
    用锁或者队列 ,插入前判断
        47
    JohnYehyo   28 天前
    服务器生成 token 存入表单隐藏字段 表单提交 服务器端获取该值与 token 比较 一致则进行业务处理并在 session 删掉 token
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3569 人在线   最高记录 5043   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 21ms · UTC 10:01 · PVG 18:01 · LAX 03:01 · JFK 06:01
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1