一个 service 引用几十个 dao 如何优化? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
smeraldo
V2EX    Java

一个 service 引用几十个 dao 如何优化?

  •  3
     
  •   smeraldo 2019 年 2 月 25 日 6463 次点击
    这是一个创建于 2532 天前的主题,其中的信息可能已经有所发展或是发生改变。
    假设一个场景:删除用户,需要同时删除所有相关的用户数据,那 DeleteService 除了引用很多很多 dao 以外有没有更好的做法?
    28 条回复    2019-02-26 12:25:31 +08:00
    Raymon111111
        1
    Raymon111111  
       2019 年 2 月 25 日
    异步的做
    smeraldo
        2
    smeraldo  
    OP
       2019 年 2 月 25 日
    发现不能编辑主题。。
    不是性能的问题,是 DeleteService 的依赖太多了,感觉是 code smell
    wfd0807
        3
    wfd0807  
       2019 年 2 月 25 日   3
    已经到 Dao 层面了,就不是 code smell 这么简单了
    是不是 DB 层面用户数据结构过度设计?是不是业务过于集中?
    总之,仅仅针对 DeleteService 无法彻底优化,顶多封装 component,隐藏 dao 的依赖(眼不见心不烦)
    lovedebug
        4
    lovedebug  
       2019 年 2 月 25 日   1
    删除用户是比较少见的操作,我这一般都是一个 db procedure
    jingxyy
        5
    jingxyy  
       2019 年 2 月 25 日   6
    使用消息队列解耦,删除用户生成一条消息扔到队列里,各相关系统订阅该事件完成各自逻辑,各相关系统控制各自对象的生命周期。
    lihongjie0209
        6
    lihongjie0209  
       2019 年 2 月 25 日
    观察者模式, 依赖一个 list<Ob>

    interface Ob{

    void onUserDelete(long userId);


    }
    lsongiu
        7
    lsongiu  
       2019 年 2 月 25 日
    消息队列+1
    jorneyr
        8
    jorneyr  
       2019 年 2 月 25 日
    例如 MyBatis 里可以一次执行多条 SQL 语句
    lihongjie0209
        9
    lihongjie0209  
       2019 年 2 月 25 日   3
    至于如何注册所有的观察者到 DeleteServer 也很简单, 初始化的时候通过"ioc.getByType(Ob.class)" 手动初始化,只要是 iocbean 之内的对象都可以自动注册到 DeleteService


    关于消息队列, 我的意见的如果只是为了解耦, 还是不要用的好, 不然你 debug 的时候就很难受了, 一个简单的系统没必要上这么重的组件
    leon0903
        10
    leon0903  
       2019 年 2 月 25 日
    @smeraldo 没出现性能问题 我觉得不用去管他。。。。。
    NoKey
        11
    NoKey  
       2019 年 2 月 25 日   1
    现在还有这么实诚的删除用户数据?
    凡事要删除的,在某张表里标记一个删除
    正常手段查不到这个数据而已
    ppwangs
        12
    ppwangs  
       2019 年 2 月 25 日
    存储过程
    leeg810312
        13
    leeg810312  
       2019 年 2 月 25 日 via Android
    只有欧盟数据保护法要求用户申请删除时必须真删数据,其他情况不都是软删除吗?
    smeraldo
        14
    smeraldo  
    OP
       2019 年 2 月 25 日
    @NoKey
    @leeg810312
    假设的场景, 不过就算是逻辑删除, 那也得操作几十张表啊
    NoKey
        15
    NoKey  
       2019 年 2 月 25 日   1
    @smeraldo 看具体实现,一般来说,我接触的,信息有消息通过一张表来体现,只要这张表表明信息无效,连带的其他表都不用查了
    reeco
        16
    reeco  
       2019 年 2 月 25 日 via Android
    事件驱动去解耦
    gejun123456
        17
    gejun123456  
       2019 年 2 月 25 日
    没啥问题,没必要优化
    Allianzcortex
        18
    Allianzcortex  
       2019 年 2 月 25 日
    我也觉得 @NoKey 的做法好,判断的时候加一个 isActivate 就好

    @jingxyy 感觉好像会更复杂...Web 系统很多时候本身并不会与 kafka 结合,加入后还要考虑 partition/HA。消息队列更适合大容量不严格要求精确处理的例子,比如日志,而用户删除账号行为是一个低频且要求严格处理的情况
    HuHui
        19
    HuHui  
       2019 年 2 月 26 日 via Android
    楼上这一波不就是典型的过度优化么
    HuHui
        20
    HuHui  
       2019 年 2 月 26 日 via Android
    @HuHui 简单的可以通过业务模块来调 service,而不是直接调各个 dao,这样也方便做其他控制,比如事务
    jingxyy
        21
    jingxyy  
       2019 年 2 月 26 日
    @Allianzcortex
    从业务的角度考虑,你说得没错,isActivate 确实是常用的一种模式。只不过使用消息队列也是一种常用的解耦手段,而且使用消息队列并不意味着一定要引入一套额外的系统,你完全可以参考其思路(类似于 reeco 说的事件驱动解耦)在应用内实现一套类似 django signal 的玩意,这样不但做到了代码解耦,也不影响操作的严格性,想上事务都可以。
    laball
        22
    laball &nbp;
       2019 年 2 月 26 日
    建议在 Service 和 Dao 之间加一层 Manager,将部分可重用的功能封装起来。
    你这里可以封装多个 Manager,每个 Manager 管理一些关联性较强的信息,这样,Service 依赖几个 Manager 即可,每个 Manger 又依赖多个 Dao。这种设计,有点类似门面模式,将复杂的细节进封装,同时,也提高了代码复用度。

    我见过有人一个 Service 依赖接近 20 个 Dao 的情况,代码确实不优雅,后期修改起来,有点密集恐惧症。
    zhix
        23
    zhix  
       2019 年 2 月 26 日
    我同意 @reeco 的方法,使用事件驱动,DeleteService 只负责核心的删除操作,在操作完成之后发布一个事件 UserDeletedEvent,然后业务就结束了。

    其他后续的删除操作委托给不同的类去完成,实现类监听 UserDeletedEvent 事件并完成后续的步骤。除此之外,UserDeletedEvent 可以包含 userId、userName 等数据供实现类获取上下文数据。
    smeraldo
        24
    smeraldo  
    OP
       2019 年 2 月 26 日
    @laball 我现在是这么做的,目前来说还好,但总感觉迭代几次以后中间的 facade dao 也会膨胀,很难符合 srp
    smeraldo
        25
    smeraldo  
    OP
       2019 年 2 月 26 日
    @zhix 嗯,理想情况下感觉这样做挺好。根据现在的实际情况,增加的复杂度可能没收益来的高
    mokeychan
        26
    mokeychan  
       2019 年 2 月 26 日
    我同意 @NoKey 的做法
    woyixinyiyi
        27
    woyixinyiyi  
       2019 年 2 月 26 日
    同意 @zhix
    我这边也有个类似的,部分 service 有自己的缓存配置,

    在定时器类,如果每个都去调用每个 service 的清空缓存,调用 service 太多,定时器发布事件,各类自行清空呗。
    johnniang
        28
    johnniang  
       2019 年 2 月 26 日 via Android
    Event-Driven 可以很好的解决这个问题。如果是单体应用的话,就直接用 Spring 自带的 ApplicationEvent ;如果是微服务就用消息中间件吧!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1376 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 17:23 PVG 01:23 LAX 09:23 JFK 12:23
    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