V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
chaleaoch
V2EX  ›  Go 编程语言

Golang 写的 web 也分 Service 和 DAO 吗?

  •  
  •   chaleaoch · 2021-09-09 14:14:13 +08:00 · 10159 次点击
    这是一个创建于 931 天前的主题,其中的信息可能已经有所发展或是发生改变。

    python 后端出身.

    第一次写 go web. 然后照着网上的开源项目抄. 我觉得 controller service Model 三层还是可以的. 毕竟业务扔到 Service 里面逻辑更清晰一些.

    然后和 Java 同事请教了一下. 令我困惑的是:

    • 类似验证密码的操作, 也要放到 Service 里面取做. 之前 django 的写法就是
    user_instance.check_passwork(request.Post['password']) 
    

    这样不行吗? 为什么一定要

    1. get password from DB
    2. checkpassword with request
    

    • Service 里面不要出现 SQL. 也就是说, 所有的查询都要用 Dao 转一手. 譬如我要查询一个用户是否存在. 如果用 Gorm 的话
    DB.Where(map[string]interface{}{"user_id":666}).Count(&count)
    

    这句话必须放在 DAO 层, 而不是直接在 Service 里写? 感觉好麻烦啊.

    我的问题是:

    1. GO 可以更灵活吗? 更灵活一些是套路吗? 在开源项目中 / 实际商业项目中有成功案例吗?
    2. Java 分这么多层是 JavaEE 带进来的还是 Spring 带进来的? 还是谁带进来的? 没人提出过异议吗?

    谢谢

    57 条回复    2024-03-25 15:32:17 +08:00
    basefas
        2
    basefas  
       2021-09-09 14:28:16 +08:00
    Go 没有严格的项目结构要求,严格来讲 Go 也不是面向对象语言,所以可以不完全按照 MVC 的架构来写。可以多看看其他的开源项目的写法。也可以看看我写的一个后台项目,以供参考。
    https://github.com/basefas/admin-go
    usedname
        3
    usedname  
       2021-09-09 14:30:48 +08:00
    只要你愿意, 你在 controller 里面写 SQL 也没有任何毛病
    chendy
        4
    chendy  
       2021-09-09 14:37:00 +08:00   ❤️ 1
    不懂 go 的 java 农表示:
    项目简单的话,把所有逻辑放一个文件里也没事
    项目复杂的话,分层可以降低理解难度,更容易维护
    这套路哪来的我不知道,但是我觉得还挺合理的
    有的时候一个不复杂的功能我也会老老实实分层,有时候一个很复杂的查询我会直接塞进 controller,具体情况具体分析吧
    rickiey
        5
    rickiey  
       2021-09-09 14:39:08 +08:00
    你可把一个工程写进一个 main 文件也没事,想写那都可以,但是工程大了你就发现你把握不住了,前人根据经验把工程分层分类,就是为了避免这种情况的,当然你牛逼的话也可以尝试自己的结构
    sy20030260
        6
    sy20030260  
       2021-09-09 14:40:54 +08:00   ❤️ 1
    1. 考虑开闭原则,例如如果后续切换存储,要做到不修改上层的业务代码逻辑,分层是不是最简单直接的方式
    2. Go 风格解构了很多传统面向对象方法论里的原则,但面向接口编程和开闭原则,Go 还是提倡的
    3. 代码分层不是 Java 独有而是程序员们的经验沉淀,虽然不一定是最佳实践,但在大部分场景下稳定工作
    cheng6563
        7
    cheng6563  
       2021-09-09 14:43:29 +08:00
    Service 和 Model 可以看情况合并一起,但请务必与 controller 层分开。
    abersheeran
        8
    abersheeran  
       2021-09-09 14:53:05 +08:00
    Java 程序员写 Django 也会有 DAO 。我见过。纯粹是他们的个人习惯。
    rimutuyuan
        9
    rimutuyuan  
       2021-09-09 14:55:53 +08:00   ❤️ 9
    我的 go 项目目录都是和 open bilibili 学的
    soupu626
        10
    soupu626  
       2021-09-09 14:59:34 +08:00   ❤️ 5
    面向接口,功能单一独立,dao 只提供数据查询的能力,不吃任何逻辑

    如果不要 service
    比如在 dao 里吃了密码校验的逻辑,那如果是加盐的密码,这个加盐过程要不要 dao 吃,如果前端传递过来也是有加密的,这个加密过程要不要 dao 吃,界限很难判定

    如果不要 dao,数据查询逻辑和业务逻辑混杂,也不便维护
    查询一个用户是否存在,现在判定下 userId 在数据库里有没有记录就行,如果某个场景要求 lv11 以上会员可参与,某个场景要求女性专场,某个场景要求未成年禁入,这种情况下,难道在 service 里写一坨一坨的 sql 么,dao 提供一个通用的用户查询接口,给一个查询参数对象,各个场景根据需要设置不同参数就行。就算现在能忍受数据查询和业务逻辑杂,要是下一步,要求用户中心独立,数据库查询要变成外调其他服务,这一堆堆的 sql 改起来可太费劲了。

    这些工程实践,都是被真实业务场景锤出来的,工程上好维护的代码才是好代码,没有维护性的代码都是屎山

    当然如果是个人项目,以上纯当放屁,怎么开心怎么来。
    HelloWorld556
        11
    HelloWorld556  
       2021-09-09 15:01:43 +08:00   ❤️ 2
    zhoudaiyu
        12
    zhoudaiyu  
       2021-09-09 15:24:39 +08:00 via iPhone
    @abersheeran 有 IxxxService 和 xxxServiceImpl 吗?
    aliveyang
        13
    aliveyang  
       2021-09-09 15:35:24 +08:00   ❤️ 5
    这个工程化的东西,跟语言无关吧
    kxiaong
        14
    kxiaong  
       2021-09-09 15:36:57 +08:00   ❤️ 1
    即使是 Django 项目,我也不太赞成 SQL 写在 service 层( views.py ).Django 的 Model 可以封装自己的 objects, 来定义通用的查询,基本等效于 java 的 DAO 。好处是对数据库的操作封闭,所有上层业务通过统一的接口修改数据。

    多人协作的 Django 项目中,没法确定别人写的 service 中有没有 SQL 修改或影响到你要操作的数据。出问题不好定位。
    PDX
        15
    PDX  
       2021-09-09 15:41:07 +08:00
    这个应该和语言无关的吧,分层设计也是经过大量实践总结才定制出来的。

    你觉得怎么舒服就怎么写,后期也是要不断优化重构的,说不定最后你自己会设计出一套层次结构呢。
    wfd0807
        16
    wfd0807  
       2021-09-09 15:59:38 +08:00
    dao 层的存在是封装持久层,隔离业务逻辑与存储对象,比如说从 MYSQL 切换到 PostgreSQL 可以不影响业务逻辑

    service 层是 spring 项目早起设计出来的,实际作用是配合切面实现事务控制,你可以把 service 层理解成事务脚本

    至于你的项目需要不需要,根据以上两点自行考虑
    Jooooooooo
        17
    Jooooooooo  
       2021-09-09 16:01:37 +08:00
    分层还真的和语言无关.

    分层想解决的问题也是独立于语言的.
    Macv1994
        18
    Macv1994  
       2021-09-09 16:04:18 +08:00
    个人习惯吧
    chaleaoch
        19
    chaleaoch  
    OP
       2021-09-09 16:18:03 +08:00
    @soupu626 #10
    如果某个场景要求 lv11 以上会员可参与,某个场景要求女性专场,某个场景要求未成年禁入,这种情况下,难道在 service 里写一坨一坨的 sql 么,dao 提供一个通用的用户查询接口,给一个查询参数对象,各个场景根据需要设置不同参数就行。
    ===================
    谢谢, 再次基础上 我们把业务更加的复杂化. 有时候我们需要 lv11 + 有孩子的女性. 是否有孩子 是从另一张关联表读取并且他们之间没有数据库层面的外键关系.

    像这样的场景是不是就应该把方法放到 Service 里面而不是 DAO 里了?

    所以想请教, DAO 里面可以带业务吗?
    hihanley
        20
    hihanley  
       2021-09-09 18:04:45 +08:00
    @basefas 我有一个问题,internal 包里面的内容不是只有直接父级才可以访问吗
    hihanley
        21
    hihanley  
       2021-09-09 18:06:38 +08:00
    @rimutuyuan 我也想学习一下,兄弟有地址吗
    libook
        22
    libook  
       2021-09-09 18:28:56 +08:00
    这个问题不应该是 XX 语言要不要写 DAO,而是当前的项目情况上来评估加一层 DAO 是否有收益。

    Java 的开发者群体是极其庞大的,也同时是良莠不齐的,很多水平不高的 Java 工程师习惯在各种项目上套用相同的架构,真正的架构师回去评估系统特点以及架构设计上的收益和成本。

    架构上的思想都是工具,能在特定场景解决特定问题,所以不管用什么语言、框架,只要觉得某个架构思想适合用来解决问题,就可以拿来用。但同时,工具不是用来制造问题的,所以如果用起来会徒增成本,那么就没必要硬上。
    soupu626
        23
    soupu626  
       2021-09-09 20:03:26 +08:00   ❤️ 1
    @chaleaoch DAO 不带业务,就是对单表的数据查询访问,如果想要一个数据层的简单业务封装,比如逻辑删除、不可见订单的过滤,多表的数据查询聚合,我们组的做法是,会抽一层 manager 出来,如果是专职数据访问的 manager,有时候会命名为 DAC
    service 之下 dao 之上再区分一层 manager 出来,在有些情况下可以提高内聚性,还是具体问题具体分析,当然如果有公司或者组内规约,还是按规约来,不然也许哪天被人在注释里一顿狂喷。。。
    zjsxwc
        24
    zjsxwc  
       2021-09-09 20:16:20 +08:00 via Android   ❤️ 2
    写 java 时会有 dao 层我个人认为是受了 mybatis 的影响,用了 mybatis 那些 xml 或者 注解 非原生代码 方案的,你是不得不用 dao 层,君不见 springboot 的 jpa 方案就没有 dao 而是用了 repository 模式, 因为 repository 是原生代码实现所以甚至可以在 repository 里注入别的业务对象,而 dao 的 xml 或者注解都只是文本字符串,根本不能注入原生语言的对象,于是迫不得已,只能在套个 dao 对象来搞良。

    题外话,绝大部分项目没有切换数据库如 mysql 换 pg 的需求,
    有很小很小部分项目有换 orm 轮子的需求,比如 beego 自带的 orm 换 gorm 。
    sanyuedev
        25
    sanyuedev  
       2021-09-09 20:31:58 +08:00
    个人觉得 DAO 可以去掉
    wangbenjun5
        26
    wangbenjun5  
       2021-09-09 20:36:16 +08:00
    一般 controller 、service 、model 3 层,model 就是 db 层,负责和数据库交互,这个少不了。

    service 层的话,其实很多简单的业务确实多余,用不上,硬是搞这一层闲的繁琐,其实可以去掉!
    chaleaoch
        27
    chaleaoch  
    OP
       2021-09-09 20:54:16 +08:00
    @zjsxwc 谢谢大佬, 你这个回答好.
    sujin190
        28
    sujin190  
       2021-09-09 20:54:33 +08:00
    java 感觉逻辑就是,分层、结构、解耦、扩展好维护,要考虑流量上来了团队壮大了如何如何,结果现实情况加班加点做完每三个月项目黄了,其实光是上半年就倒闭了数十万家公司,能做起来的少之又少,想这么多都是有的没的,特别是 mybatis 这一套,小公司使用场景来看设计的简直神经病一样的,所以依据自己现实和工程方法,选择合适的方案就可以了,没必要硬套这些东西
    yrj
        29
    yrj  
       2021-09-09 21:53:01 +08:00 via iPad   ❤️ 1
    我的方式,直接 gorm 写 service 里,不用 dao 。
    zand
        30
    zand  
       2021-09-09 22:04:36 +08:00
    @kxiaong 赞同,python 不背这个锅,使用 Django 的项目也应该有良好的分层,一味求简单只是给后来人挖坑。
    比如需要分库分表时,满山遍野的 objects 真的让人崩溃。
    fiypig
        31
    fiypig  
       2021-09-09 22:35:08 +08:00 via iPhone
    分控制层跟模型层
    chaleaoch
        32
    chaleaoch  
    OP
       2021-09-09 23:07:12 +08:00
    @zand 但是在开源项目里. 我没见过像你说的那么用的啊. 你有例子吗? 我学习一下.
    chaleaoch
        33
    chaleaoch  
    OP
       2021-09-09 23:07:47 +08:00
    @yrj 和我想的一样 默认我也想这样用.
    forbreak
        34
    forbreak  
       2021-09-10 09:07:57 +08:00
    分不分层是自己决定的,跟语言无关,跟工程化有关。实际项目你想咋写咋写,没有语言会限制你。
    anonydmer
        35
    anonydmer  
       2021-09-10 09:19:32 +08:00
    楼主先前 django 写那个密码验证没有写单元测试吧
    jetyang
        36
    jetyang  
       2021-09-10 09:31:32 +08:00
    楼主说到 java web 程序员的痛处了
    anonydmer
        37
    anonydmer  
       2021-09-10 09:32:35 +08:00   ❤️ 2
    忍不住想说两句

    1. DAO 是个很古老的东西,不是伴随 mybatis,hibernete 这些产生的;事实上,早在 EJB 时代就有它了
    2. DAO 全称是 Data Access Object, 不是 Database Access Object ;所以把它狭隘的理解成适配多个数据库是不好的;事实上,这一层可以从数据库获取数据,也可以从文件系统获取数据,还可以从网络远程获取数据;
    3. 除了适配不同持久层之外,DAO 还有个重要的作用的是做持久化数据和模型直接的转换,比如存储字段和模型字段的差异,一些特殊格式的处理;这也是在实际工作中经常需要用到的

    至于用不用 DAO 或者类似 Repository 这一层,如果说项目只需要考虑一个数据库,没有任何模型和存储的格式差异,很多人选择不要这一层;不过咱们可以不用,但是得知道为什么不需要用。 不过我相信没用这一层的同学,大多数业务层代码肯定没有写单元测试吧。
    basefas
        38
    basefas  
       2021-09-10 09:42:49 +08:00
    @hihanley #20 对的,所以项目中,internal 包是全局可以访问的,但是当别人 import 你的项目时,就不能调用 internal 中的方法,如果你不在意这些,就完全可以不用这个命名,起个你喜欢的名字
    cslive
        39
    cslive  
       2021-09-10 09:49:35 +08:00
    工程规范而已,java 你可以直接在 jsp 里写,全部业务逻辑,sql,html,js 都在 jsp 里写,这样我估计你自己也不想看
    ElmerZhang
        40
    ElmerZhang  
       2021-09-10 10:23:45 +08:00
    项目小了怎么写都行,项目大了要找适合这个项目的写法。写 web 服务或者 api 服务,controller service Model 三层结构的适用性是最广的,但并不一定适用于你的项目。
    先写吧,写着写着可能就会发现怎样怎样写更好一些,然后再重构呗。
    我个人经验经验是这样的:某个 model 自身有些特定逻辑,并且在多个 service 中都会用到,那么可能需要抽出一个 dao 层来做。
    另外如果针对 model 有缓存的话,service 和 model 之间可能也要加一层,叫 manager 之类的。
    简单来说,当你在同一层的多个文件中经常 copy&paste 代码的时候,就要考虑提出一层或者提个 util 出来了。
    ytll21
        41
    ytll21  
       2021-09-10 10:54:59 +08:00   ❤️ 1
    说明楼主平时不怎么写单元测试,或者在单元测试里,是把业务逻辑和持久逻辑放在一块做测试的。
    onion83
        42
    onion83  
       2021-09-10 11:27:16 +08:00
    杠精:微服务我来了!一个表一个 RPC 服务,再加一个数据组装层,完美!
    zjsxwc
        43
    zjsxwc  
       2021-09-10 12:08:36 +08:00
    @anonydmer 2 小时 28 分钟前
    基于历史缘故,我明白你的意思,
    但 DAO 如果还是定义成 Data Access Object 这个理解,
    那么 service 和 DAO 有什么区别呢,
    只要是返回数据 Data 的对象都可以被称为 DAO,
    很少存在业务代码不使用数据的,
    那么按照这个理解一切皆 DAO !

    我也见过,在一个 foo DAO 通过多个不同 RPC 调用别的 service 对象,这些 service 对象再通过自己的 DAO 获取数据,foo DAO 再组装这些 rpc 数据返回的合成一个数据,这时候这个 foo DAO 如果按你的理解当然可以被称为 DAO,但我更愿意称呼他为 service 。
    zjsxwc
        44
    zjsxwc  
       2021-09-10 12:11:10 +08:00
    最后 DAO 就被滥用成 现在这种局面,什么都能往 DAO 里套,
    DAO 就是神,祂无所不能!
    leoskey
        45
    leoskey  
       2021-09-10 12:15:03 +08:00
    分层是为了提供系统可维护性。DAO 并不是为了可迁移到另一数据库而存在,而是在于让 Service 层更关注业务逻辑,无需关注 DAO 等底层。
    brucedone
        46
    brucedone  
       2021-09-10 12:54:02 +08:00
    以前用 echo 或者 gin 的时候,常规的就三层,能 hold 的住小项目向中项目演变,后来用了 goframe,能 hold 的住小,中,大的项目需求,是否需要 dao,我感觉更多的是看需求增长量级,再好的项目架构,也没有办法适应海量的需求变化
    jsuly
        47
    jsuly  
       2021-09-10 13:12:12 +08:00
    可以不考虑分层, 分模块
    cassyfar
        48
    cassyfar  
       2021-09-13 04:36:33 +08:00
    @zjsxwc
    DAO 是去调用持久数据的,就是你服务器挂了,这些数据也会在。比如存在数据库里,存在本地磁盘文件里或者其他地方的数据。我个人理解 DAO 只是将你自己系统处理数据的逻辑,和如何存储这些数据的逻辑分离开( decouple )。这样比如你升级更换迁移数据的持久方案,也不会影响到你本身的服务。
    HHAO2019
        49
    HHAO2019  
       2021-09-14 09:01:22 +08:00   ❤️ 1
    controller->service->manager->mapper 我这边项目是这样的 Java
    chaleaochexist
        50
    chaleaochexist  
       2022-04-13 09:51:02 +08:00
    @kxiaong #14 views.py 是 service 的话,controller 是什么?
    chaleaochexist
        51
    chaleaochexist  
       2022-04-13 09:54:02 +08:00
    chaleaochexist
        52
    chaleaochexist  
       2022-04-13 09:55:33 +08:00
    @wfd0807 #16 大佬,我其实也一直在查这个三层架构是从哪里来的。
    “service 层是 spring 项目早起设计出来的” 这个有出处吗?
    chaleaochexist
        53
    chaleaochexist  
       2022-04-13 10:03:06 +08:00
    @anonydmer #37 你说的这三点 django 中的 model 都能实现。
    不过 django 中的 model 的功能 会更多一些, 譬如可能带一些 业务。 这又和 DAO 不一样了。
    譬如 获取一个用户的多个 Role 这样的操作在 Java 里面 一般都在 service 里写。但是在 django 中可能就是一个 model 的方法了。
    chaleaochexist
        54
    chaleaochexist  
       3 天前
    @zjsxwc 时隔数年在看自己的问题. 有了新的理解.
    大佬请教一下 repository 和 DAO 有什么区别?

    我怎么感觉都差不多呢?
    除了
    1. 面向领域和面向数据.
    2. entity 可以带方法.

    能举个例子吗?
    chaleaochexist
        55
    chaleaochexist  
       3 天前
    @abersheeran java 写 DAO 怎么写?
    DAO 绑定一个 Model?
    chaleaochexist
        56
    chaleaochexist  
       3 天前
    @soupu626 时隔多年又回到这个问题.

    你说的我有一点点理解.

    但是如果是 django 来作的话, 有一点点类似于 java 中的 entity/pojo 拥有一个方法去查询数据库.
    User user = new User()
    user.checkpasswd()

    这样子.
    chaleaochexist
        57
    chaleaochexist  
       3 天前
    @kxiaong
    "Django 的 Model 可以封装自己的 objects, 来定义通用的查询,基本等效于 java 的 DAO"
    只能说基本等效, 就像其他楼说的, 如果涉及到 Redis 操作或者其他 RPC 操作, 如果自己封装一层 DAO 更清晰.
    还有就是换 ORM 的时候, 如果自己封装了一层 DAO, 那么 service 层真的一点都不用动. 但是如果 django orm --> 换别的 ORM. service 层要改动的地方还是挺多的.
    说白了 还是面向接口编程
    "多人协作的 Django 项目中,没法确定别人写的 service 中有没有 SQL 修改或影响到你要操作的数据。出问题不好定位"
    即使是使用 DAO 也无法定位有没有 SQL 修改影响你的操作啊.
    譬如 user 和 permission 两张表.
    我在 UserDao 中是否可以处理 Permission 这张表呢?
    譬如删除 User 同时删除 Permission 这个动作是在 Service 里调用 PermissionDao 还是在 UserDAO 中直接把 permission 直接删除了? 这个有规范吗?

    补充, 我是楼主, 感谢大佬的原始回复.
    期待您新的回复.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3395 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 46ms · UTC 11:16 · PVG 19:16 · LAX 04:16 · JFK 07:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.