zoukankan      html  css  js  c++  java
  • 因网络延迟造成数据库插入相同记录,如何解决.

    场景:导入会员数据,出现了重复数据在库里面。导入过程中有身份证号的唯一检查,怎么还会重复呢。百思不得其解。。。

    万恶的网络延迟。。。。

    仔细查了遍代码,发现身份证号检查速度特别慢,造成了网络阻塞。。。

    对于用户来说不知道怎么回事(以为没反应),点击了导入。。。两个线程之间几乎没有时间差。所以即使有检查,也没管用。

    解决案

    1.优化身份证号的检查,并在表中为身份证号加索引

    2.mybatis上做的手脚,重复时候不插入。

    • 1.如果某些关键字段已经在Mysql中存在了,不要重复插入,而是改为更新某些字段。
    • 2.如果某些关键字段已经在Mysql中存在了,不要重复插入,也不需要做更新操作,直接忽略即可。

           1、针对上面的第一种,mysql提供了insert into ... on duplicate key update ... 语法(Mysql自己的语法,不属于标准SQL)来实现。这种场景相对常见。使用的前提是,需要定义主键或者           唯一性索引,用来告诉Mysql哪些字段的重复会造成主键冲突或者违背唯一性约束条件。当这些情况出现时,就放弃insert操作,转而执行后面的update操作。上一个具体的例子,在ibatis           中写的一个上面逻辑的sql:

             Xml代码  收藏代码
    1. <statement id="testInsertOnDuplicateKeyUpdate"  
    2.             parameterClass="com.alibaba.ais.bdc.person.dataobject.UserInfo">  
    3.      <!--Here the employ_id has been defined as a primary key-->  
    4.      insert into T_USER_INFO (employ_id,fans_count,follow_count)  
    5.      values (#employId#,#fansCount#,#followCount#)  
    6.      ON DUPLICATE KEY UPDATE follow_countfollow_count=follow_count+1  
    7. </statement>  

           上面的插入操作就会在employ_id发生主键冲突的时候,转变为更新follow_count字段(自增一个单位)。

    2、针对上面的第二种,mysql提供了insert ignore into ... 语法(Mysql自己的语法,不属于标准SQL)来实现。这种场景相对要少见一些。 使用的前提是,需要定义主键或者唯一性索引,原因同上面一致。但不同的就是,违背唯一性约束时,直接忽略这次insert操作,然后啥也不干了,也不会报错。。。

    但这里有个问题,就是有时业务本身还是需要知道语句到底执行了insert还是没有执行!因为需要根据这个反馈信息,做出不同的处理逻辑。这里给出使用ibatis时,两种不同的处理方法。

    • 借助mysql的内置函数row_count()和ibatis的selectKey标签:
      • 关于ibatis的selectKey标签,更为常见的用法是在插入对象到DB之后,返回DB自增产生的主键ID。比如:
        • Xml代码  收藏代码
          1. <insert id="testSelectKey">    
          2.           insert into T_TEST(WATCHER, WATCHEE) values (#watcher#,#watchee#)  
          3.           <selectKey resultClass="int" keyProperty="id">  
          4.               select last_insert_id() as ID from dependency limit 1  
          5.           </selectKey>  
          6. lt;/insert>  
           
        • 通过上面语句进行插入操作之后,可以通过如下方式在Java代码中获得这个DB自增产生的ID:
        • Java代码  收藏代码
          1. Integer id = (Integer) sqlMapClient.insert("testSelectKey", param);    
      • row_count()是Mysql提供可以获得insert、update、delete这几种操作成功处理行数的一个内置函数,有了这个函数,再结合上面给出的selectKey标签的例子,就可以做到获得insert ignore时,成功insert的行数。有了这个行数,也就知道了到底有没有发生insert操作。(发生了插入操作该函数返回值会大于0),于是改编一下上面的sql-map中的sql(注意其中的ignore关键字):
        • Xml代码  收藏代码
          1. <insert id="testInsertIgnore">    
          2.           insert ignore into T_TEST(WATCHER, WATCHEE) values (#watcher#,#watchee#)  
          3.           <selectKey resultClass="int" keyProperty="id">  
          4.               select row_count() as ID from T_USER_RELATION limit 1  
          5.           </selectKey>  
          6. lt;/insert>  
          通过上面语句进行插入操作之后,可以通过如下方式在Java代码中获得insert真正影响到的行数:
        • Java代码  收藏代码
          1. Integer affectedRows = (Integer)sqlMapClient.insert("testInsertIgnore", param);  
           
    • 利用ibatis的update语句:上面之所以要费劲周折的修改insert语句,时因为ibatis本身的insert不是默认支持返回影响的行数的。但是update语句支持!于是,另外一个思路,就是利用update语句来完成这个insert操作。
      • Xml代码  收藏代码
        1. <update id="testInsertIgnore">  
        2.        insert ignore into T_USER_RELATION(WATCHER, WATCHEE) values (#watcher#,#watchee#)  
        3.        <!--Without selectKey tag, it looks mush more concise-->  
        4.    </update>  
         通过上面语句进行插入操作之后,可以通过如下方式在Java代码中获得insert真正影响到的行数(这里需要注意的是,Java代码中需要使用sqlMapClient的update的API哦):
      • Java代码  收藏代码
        1. Integer affectedRows = (Integer)sqlMapClient.update("testInsertIgnore", param);  

    教训:可能开发人员为了省事,喜欢共用sql文。但是一个小小的检查其实是不需要关联那么多表的。共用后,导致检查时间过慢。

              特别是表数据量较大的时候非常明显。建议,新写个检查的sql

  • 相关阅读:
    https://scrapingclub.com/exercise/detail_sign/
    https://scrapingclub.com/exercise/basic_captcha/
    https://scrapingclub.com/exercise/basic_login/
    344. 反转字符串(简单)
    142. 环形链表 II(中等)
    面试题02.07.链表相交
    19. 删除链表的倒数第 N 个结点
    24.两两交换链表中的节点
    206.反转链表(简单)
    707.设计链表
  • 原文地址:https://www.cnblogs.com/taiyanhong/p/7249393.html
Copyright © 2011-2022 走看看