Home  >  Q&A  >  body text

PHP和mysql中,如何防止数据重复insert?

因为运行的时候有延迟。

sql1 = SELECT * FROM posts WHERE mid = 2

sql2 = INSERT INTO posts (id,mid,other) VALUES ('',".$c.",'def');

因为用了for 循环。首先是检测是否存在Sql1,如果不存在,则sql2。
再重复循环。可是,当前sql2第一次没有运行insert时,第二次循环的时候执行Sql1是通过的,然后再次执行sql2,导致运行了两次sql2。

可能同时触发了一个链接,这样导致重复插入了。
综合几位朋友的说法,我决定不在这个循环里面插入数据。

但好像:
用 INSERT INTO posts (id,mid,other) VALUES ('',".$c.",'def'),('','c2','def2'),('','c2','def2'),('','c2','def2');
这样子不行,因为假如其中一个出错,那么整条就好像就不能插入了。

谢谢大家的解答,我再去试了下我想到的几种方式~谢谢~

这个要怎么处理呢?

听说要用事务处理,但是不懂如何使用。手册已经看过了,但不明白。。。

[以下只是举例子]
$c 是 变量, mid 字段不能设置为“唯一”


$c = '10000'; for($a = 0;$a < 100; $a++){ $sql1 = "SELECT * FROM `posts` WHERE `mid` = ".$c; $query1 = mysql_query($sql1); $row = mysql_num_rows($query1); if($row == 0){ $sql2 = "INSERT INTO `posts` (`id`,`mid`,`other`) VALUES ('',".$c.",'def')"; $query2 = mysql_query($sql2); }

}

ringa_leeringa_lee2654 days ago405

reply all(7)I'll reply

  • 天蓬老师

    天蓬老师2017-04-10 14:46:19

    问题描述的不是很清晰,

    可是,当前sql2第一次没有运行insert时,第二次循环的时候执行Sql1是通过的,然后再次执行sql2,导致运行了两次sql2。

    上面这句话没看懂什么意思

    首先,在循环里面做sql查询是相当低效的,强烈建议你修改逻辑,避免这种情况

    关于你举例子的那段for循环代码,两个优化方案
    其一,在循环里拼接insert的数组,大概代码如下

    $d = [];
    for($i = 0; $i < 100; $i++)
    {
        $r = mt_rand(1, 100);
        //排除重复值,
        if(!in_array($r, $d))
        {
             $d[] = $r;
        }
    }
    $pdo = new PDO($dsn, $user, $passwd);
    $pdo->prepare("insert into table(col1,col2) values(?,?)");
    foreach($d as $v)
    {
        $pdo->execute(array($v, $v));
    }
    

    如上,复用insert语句模板,同时也排除了可重复插入的数值,如果对每一组值有特殊处理,也可以放在foreach处理
    我很推荐你使用此种方式,这种方式也是安全的,能良好的预防sql注入,而无需你再去考虑太多sql注入的问题

    其二,拼接一个比较长的insert的语句,

    insert into table_name(col1,col2, ......) values(v1,v2,......),(v1,v2,......),......
    

    上述二者可能并不切合题意,因为可能之前库里就存在和当前插入有重复的数据
    在mysql里有如下sql语法

    INSERT INTO TABLE (a,b,c)
    VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
    

    上句中的意思就是,插入一条语句到表中,如果插入的数据和表中唯一索引或者主键重复,更新字段c的值

    结合这个sql语句,能很完美解决插入值重复的问题吧?

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 14:46:19

    循环里敢这么玩!

    reply
    0
  • 大家讲道理

    大家讲道理2017-04-10 14:46:19

    不懂你这个$sql1判断的意义何在,设置id这个是唯一key不就好了么?而且同 @宋小北 循环里面敢这么玩!!

    今天看到个文章和这个问题非常契合,特此补上:http://blog.sae.sina.com.cn/archives/3491 -2014/04/17 12:41

    reply
    0
  • PHP中文网

    PHP中文网2017-04-10 14:46:19

    只要在'posts'的表,加上唯一UNIQUE即可,或者當然可以用

    INSERT INTO
    table(column1,column2,column3 ...columnN)
    SELECT value1,value2,value3 ...valueN
    FROM dual
    WHERE NOT EXISTS(
    SELECT *
    FROM table
    WHERE value = ?
    );

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 14:46:19

    先查询可用的mid, 再插入数据

    $variable_array = array();
    $c = 1000;
    for($a = 0;$a < 100; $a++){
        $variable_array[] = $c;    
    }
    if (count($variable_array) == 0) {
        return false;
    }
    // 去重
    $variable_array = array_unique($variable_array);
    // 获取可用mid
    $sql_head = "SELECT `mid` FROM `posts` WHERE `mid` in (#variable#) ";
    // 加上单引号, 如果确定都是数字,那就不加
    $mid_array = array_map(function($value){return "'$value'";}, $variable_array);
    $mid_list = array();
    foreach (array_chunk($mid_array, 500) as $piece) {
        $variable_str = implode(",", $piece);
        $sql_piece = str_replace("#variable#", $variable_str, $sql_head);
        $query_piece = mysql_query($sql_piece);
        // 获取mid $mid_piece
        $mid_piece = mysql_fetch_array($query_piece);
        $mid_list = array_merge($mid_list, array_diff($piece, $mid_piece););
    }
    // 插入数据库
    $insert_str_array = array_map(function($value){return "('', '$value', 'def')";}, $mid_list);
    $insert_head = "INSERT INTO `posts` (`id`,`mid`,`other`) VALUES ";
    foreach (array_chunk($insert_str_array, 500) as $piece) {
        $variable_str = implode(",", $piece);
        $insert_sql = $insert_head.$variable_str;
        mysql_query($insert_sql);
    }
    

    很久没写php代码, 怎么获取mysql_query结果忘记了!!!直接用得mysql_fetch_array.

    reply
    0
  • PHPz

    PHPz2017-04-10 14:46:19

    1.唯一索引。2.按照特征拿相关数据,进行对比

    reply
    0
  • 黄舟

    黄舟2017-04-10 14:46:19

    试试

    replace into `table` values set  key=val
    

    reply
    0
  • Cancelreply