首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
宝塔
V2EX  ›  Java

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

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

    interface Ob{

    void onUserDelete(long userId);


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


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

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

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

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

    在定时器类,如果每个都去调用每个 service 的清空缓存,调用 service 太多,定时器发布事件,各类自行清空呗。
        28
    johnniang   265 天前 via Android
    Event-Driven 可以很好的解决这个问题。如果是单体应用的话,就直接用 Spring 自带的 ApplicationEvent ;如果是微服务就用消息中间件吧!
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3627 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 22ms · UTC 10:08 · PVG 18:08 · LAX 02:08 · JFK 05:08
    ♥ Do have faith in what you're doing.