请教大佬, springboot+mongodb 如何效率的更新整个实体类 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
NoKey
V2EX    程序员

请教大佬, springboot+mongodb 如何效率的更新整个实体类

  •  1
     
  •   NoKey 2019-08-20 23:46:34 +08:00 3996 次点击
    这是一个创建于 2299 天前的主题,其中的信息可能已经有所发展或是发生改变。
    基于 springboot+mongodb 做一个系统
    有一个场景,保存了全公司的员工信息( 3 万+)
    定时会从 mysql 库同步员工信息,如果员工信息有改动(有一个版本号可以比较),mongodb 里就需要更新
    但是。。。但是。。。我不知道到底哪个信息修改了
    员工信息字段有几十个
    如果要一个一个的比较,要写好多判断语句
    然后,我找了 MongoTemplate 又一个方法 findAndReplace
    但是,效率很低,测试一下,更新 1 万多人,需要 5 分钟左右(测试服务器),这段时间,用 robo 3T 工具去打开数据表,会卡住
    哪位大佬知道,有没有更好更快速的方法呢?
    谢谢
    23 条回复    2020-03-18 21:42:39 +08:00
    kkkkkrua
        1
    kkkkkrua  
       2019-08-21 00:15:39 +08:00 via iPhone
    我曾经也考虑过类似的问题
    如何系统的考虑修改字段的新值和旧值的记录,后面考虑了下,可以把记录做副本保存,再加上时间戳,对比的话只用对比最近的两个记录就行
    缺点是数据比较大,算法如何实现,我还没落地。
    Takamine
        2
    Takamine  
       2019-08-21 00:18:43 +08:00 via Android
    直接更新这个员工的全部数据快,还是找一遍更新某几个字段快。_(:з」∠)_
    如果时效性要求不高,感觉可以丢到队列慢慢消费。
    429463267
        3
    429463267  
       2019-08-21 00:24:54 +08:00   1
    监控 mysql 执行日志,mysql 集群主从复制就是这个原理,读取 mysql 执行日志以后,转换成 mongodb 语法到 mongo 执行
    luckylo
        4
    luckylo  
       2019-08-21 07:57:21 +08:00 via Android
    换个方式。你这是定时同步。假设你更新员工信息,就往消息队列里丢一个消息,mongodb 这个服务接收消息并更新员工信息,这样或许好一丢丢。
    NoKey
        5
    NoKey  
    OP
       2019-08-21 09:10:43 +08:00
    @luckylo 谢谢回复。实际问题,就是无法这样,如果能这样,就没有我的问题了,现在的状况就是,只能在一定时间之后获取一次,而不能在每次有修改的时候,同步一下。这个一定时间之后,不可控,或许来一个较大的部门变动,就会涉及很多人。。。
    wdmx007
        6
    wdmx007  
       2019-08-21 09:38:29 +08:00
    用反射去对比字段可以少写判断 /手动滑稽
    DsuineGP
        7
    DsuineGP  
       2019-08-21 10:01:25 +08:00
    javers 了解下
    notreami
        8
    notreami  
       2019-08-21 10:19:51 +08:00
    为啥要定时呢?准实时不行嘛?
    mysql 数据有变动就发一个变更消息出来,直接更新 mongodb 不就可以了?
    Kaiv2
        9
    Kaiv2  
       2019-08-21 10:21:56 +08:00 via Android
    时效性要求不高是不是可以弄个定时任务跑下
    NoKey
        10
    NoKey  
    OP
       2019-08-21 10:43:49 +08:00
    @notreami 原来的服务已经写好了,不能动,所以无法再修改信息的时候给个消息过来
    NoKey
        11
    NoKey  
    OP
       2019-08-21 10:45:08 +08:00
    @Kaiv2 就是定时任务,但是感觉更新的很慢
    energetic
        12
    energetic  
       2019-08-21 10:47:44 +08:00
    看起来你似乎用的是逐个更新的方法,建议试试先查出所有需要更新的员工信息,不用比较哪些字段变化,用 bulkOps 方法批量整体更新
    liuhuansir
        13
    liuhuansir  
       2019-08-21 10:49:06 +08:00
    半夜跑定时任务,影响很小吧,慢点就慢点,5 分钟也还好吧?
    NoKey
        14
    NoKey  
    OP
       2019-08-21 11:15:35 08:00
    @liuhuansir 关键是为了更新效率性,又不能设置为半夜来跑,定时 2-3 小时跑一次,
    NoKey
        15
    NoKey  
    OP
       2019-08-21 11:17:53 +08:00
    @energetic 谢谢回复,我看了一下 bulkOps 需要自己写一个 update,但是人员信息太多,得一个一个的过一遍才写的多 update,这个是很痛苦的。。。
    Kaiv2
        16
    Kaiv2  
       2019-08-21 11:35:46 +08:00 via Android
    把数据分片处理下
    br00k
        17
    br00k  
       2019-08-21 13:10:24 +08:00 via iPhone
    这么点数据。实时性要求不高就按数据 update 时间定时同步就行了。实时性要求高就用 MQ。
    artikle
        18
    artikle  
       2019-08-21 15:18:49 +08:00
    定时任务+时间断点。
    每 5 分钟或者 10 分钟跑一次脚本,去数据库拉取更新时间为,上一次时间断点到当前时间这一批次的所有数据 批量更新到 MongoDB,再将断点时间更新为当前时间。
    ShellMings
        19
    ShellMings  
       2019-08-21 17:57:19 +08:00 via iPhone
    其实你可以在 mysql 里新建一张和员工表一样结构的表,每次修改员工信息时那张表只存员工 id 和他修改过的字段,当然真正的员工表里的信息也要改,再加一个 lastEditTime 在新表里这样你就知道谁在什么时候改了些什么。
    Juszoe
        20
    Juszoe  
       2019-08-21 19:38:02 +08:00
    mysql 做个触发器,把更新的员工 id 放到新表中,记录更新时间,然后从这个表得知哪些被修改了,这样可以不?
    TestCode
        21
    TestCode  
       2019-08-21 21:24:37 +08:00
    我觉得这样比较好,数据库那头用一个触发器,一旦有员工信息修改便将修改相关信息放入消息队列,另一端消费。
    LeeSeoung"
        22
    LeeSeoung  
       2019-08-22 10:11:27 +08:00
    "员工信息字段有几十个
    如果要一个一个的比较,要写好多判断语句"

    mysql 跟 mongodb 分别取回来的实体类 自己写一个反射遍历所有成员进行比对,很容易得到差异点吧,可以写成通用的,并不需要一个一个写。
    wxb2dyj
        23
    wxb2dyj  
       2020-03-18 21:42:39 +08:00
    以下是我的方法

    //CommonUtil.java
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.BeanWrapper;
    import org.springframework.beans.BeanWrapperImpl;
    ....
    public static void copyNonNullProperties(Object src, Object target) {
    BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }

    private static String[] getNullPropertyNames(Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    PropertyDescriptor[] pds = src.getPropertyDescriptors();
    Set<String> emptyNames = new HashSet<>();
    for (PropertyDescriptor pd : pds) {
    String propertyName = pd.getName();
    Object srcValue = src.getPropertyValue(propertyName);
    if (srcValue == null) {
    emptyNames.add(pd.getName());
    }
    }
    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
    }

    //获取新 /旧员工信息,newEmployee 是新的员工信息,originalEmployee 是旧的员工信息
    Employee originalEmployee = readFromYourMongoDB();
    Employee newEmployee = readFromYourMySQL();
    //该方法将会更新 originalEntity,而且只更新相对 newEntity 中变化的字段
    CommonUtil.copyNonNullProperties(newEmployee , originalEmployee );
    //重新保存 originalEmployee 到 MongoDB
    ObjectId objectId = new ObjectId();
    Date date = objectId.getDate();
    //保存更新时间
    originalEmployee.setUpdateTime(objectId.getDate());
    employeeRepository.save(originalEmployee);
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1335 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 17:03 PVG 01:03 LAX 09:03 JFK 12:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86