V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mangojiji
V2EX  ›  数据库

Mybatis 到底是或不是 ORM?为什么?

  •  1
     
  •   mangojiji · 2023-11-23 06:16:26 +08:00 · 3713 次点击
    这是一个创建于 400 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我觉得它是,因为它确实可以将对象保存到数据库也可以从数据库里检索到对象,
    但隐约感觉哪里好像又有点不对劲。。

    它和 hibernate 以及 ebean 之流的框架到底谁是 ORM ,如它不是 ORM ,那么究竟是缺失了什么特征呢?
    35 条回复    2023-11-24 15:57:56 +08:00
    ChoateYao
        1
    ChoateYao  
       2023-11-23 08:52:39 +08:00
    不是,人家就是 Object Mapper ,缺少关系连接和业务逻辑实现。
    Goooooos
        2
    Goooooos  
       2023-11-23 08:53:54 +08:00
    你理解的 ORM 是啥?
    Masoud2023
        3
    Masoud2023  
       2023-11-23 09:27:18 +08:00
    按我的理解能手写 sql 的都不叫 ORM ,ORM 应该是 SQLAlchemy 那种直接能拿模型生成 SQL 的
    wanguorui123
        4
    wanguorui123  
       2023-11-23 09:38:56 +08:00
    1 、思想:
    mybatis 面向过程开发

    JPA ( Hibernate )面向对象开发

    2 、侧重点:
    mybatis 采用 XML 管理 SQL 比较直观,查询多的场景比较自由灵活、缺点存一些符号冲突(<>),管理思想还是面向过程,需要通过 Plus 加强对象管理

    JPA 将数据库完全映射为对象需要有业务的整体设计能力,JPA 优势是简单的 CURD 根本不写 SQL ,JPA 缺点就是需要了解数据状态同步管理,复杂的业务尤其需要了解实体各个阶段状态,以及复杂的连表查询需要调用 JPA 的原生查询接口或者 DSL

    3 、抽象能力
    mybatis 使用原生的 SQL 方言,迁移能力比较差

    JPA 使用 HQL 屏蔽了底层方言差异抽象的比较彻底,迁移能力比较强
    weijancc
        5
    weijancc  
       2023-11-23 09:55:49 +08:00
    这个问题被讨论烂了都, 明明百度就有一堆答案
    kevinlia0
        6
    kevinlia0  
       2023-11-23 10:15:27 +08:00
    By chatgpt

    MyBatis 是一种持久层框架,通常被称为数据映射框架( Data Mapping Framework ),而不是严格意义上的对象关系映射( ORM )框架。尽管它与 Hibernate 等 ORM 框架有一些相似之处,但它们之间存在一些关键的区别。

    1. **SQL 控制:** MyBatis 更注重对 SQL 的控制,它允许开发者编写和优化原生 SQL 查询,而不是完全依赖于框架生成的 SQL 。这使得开发者可以更细粒度地控制数据库访问,针对复杂的查询进行优化。

    2. **映射方式:** 在 MyBatis 中,对象和数据库表之间的映射是通过 XML 或注解进行配置的,而不是像 Hibernate 那样完全基于对象的映射。这意味着在 MyBatis 中,你需要显式地指定如何将对象属性映射到数据库列,而在 ORM 框架中,这一切通常是自动完成的。

    3. **对象状态:** 在 ORM 框架中,对象通常处于持久化状态,而在 MyBatis 中,对象通常是短暂的,它们只在执行 SQL 语句时与数据库进行交互。这使得 MyBatis 更加适用于需要精细控制数据库访问的场景。

    总的来说,尽管 MyBatis 可以执行对象到数据库表的映射和数据库查询结果到对象的映射,但它更强调 SQL 的控制和灵活性,相较于 Hibernate 等严格的 ORM 框架而言更接近数据映射框架。因此,如果你更喜欢自己编写和优化 SQL 语句,或者需要处理复杂的数据库操作,MyBatis 可能是一个更好的选择。如果你更倾向于对象的自动映射和更高级的持久化管理,那么 Hibernate 等 ORM 框架可能更适合你。
    iceloop
        7
    iceloop  
       2023-11-23 10:56:10 +08:00
    ORM 框架的核心是自动化地将对象模型映射到关系型数据库,Mybatis 一个垃圾的 SQL 映射框架,无论怎么说都够不上 ORM ,中国特色开发主义才让 Mybatis 在中国有地位,早应该被时代洪流淘汰的垃圾产物
    burymme11
        8
    burymme11  
       2023-11-23 11:05:12 +08:00   ❤️ 5
    我一点都不觉的 mybatis 垃圾,复杂的 sql 处理直接写在 xml 里,直观明了,排错调试很方便。
    使用 ORM 框架还能用出优越感?这玩意还能搞出鄙视链? WFT ??
    Mandelo
        9
    Mandelo  
       2023-11-23 11:09:29 +08:00
    半 ORM
    totoro52
        10
    totoro52  
       2023-11-23 11:31:40 +08:00
    @burymme11 mybaits-plus 无敌 JPA 业务逻辑复杂点的时候代码那是给人看的吗 那个 SQL 跟牛皮癣一样贴在上面一大坨 受不了受不了
    totoro52
        11
    totoro52  
       2023-11-23 11:32:17 +08:00
    @totoro52 但是业务简单的肯定首选 JPA
    XCFOX
        12
    XCFOX  
       2023-11-23 12:04:17 +08:00   ❤️ 2
    跟 C# 的 EF Core 比,MyBatis 最多算一个 SQL Builder 。
    好的 ORM 应该尽可能减少 SQL 的书写,尽量自动化,尽量贴近语言原生语法。
    看过 C# 的 Entity Framework 、Ruby 的 Active Record 、php 的 Eloquent 、Typescript 的 MikroORM 、kotlin 的 Ktorm
    才知道什么是好用的 ORM 。相比之下 Java 、go 生态下缺少好用的 ORM 框架。

    优雅的 ORM (EF Core)是这么更新的:
    using (var context = new BloggingContext())
    {
    var blog = context.Blogs.Single(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    context.SaveChanges();
    }
    使用 C# LINQ 表达式写查询,直接修改 blog.URL 的值再保存修改,真正的面向对象、真正的自动化,开发人员甚至不需要深入了解 SQL ,极大减轻了开发时的负担;

    GORM 是这么更新的:
    db.Model(Blog{}).Where("Url = ?", "http://example.com").Updates(Blog{Url: "http://example.com/blog"})
    在 gorm 自身的语法 "db.Model().Where().Updates()"之中混入半句 sql "url = ? ",这就要求开发人员既要会 sql 也要熟悉 gorm 额外的语句,开发时的性质负担并没有减少;
    kidlj
        13
    kidlj  
       2023-11-23 12:09:14 +08:00
    @XCFOX 了解下 Go 的 ent 先?
    XCFOX
        14
    XCFOX  
       2023-11-23 12:33:16 +08:00
    @kidlj #13
    ent 是这么更新的:
    n, err := client.Blog.
    Update().
    Where(
    blog.Url("http://example.com"),
    ).
    SetUrl("http://example.com/blog").
    SetTitle("The Last Theorem").
    SetAuthor("Clarke").
    Save(ctx)

    ent 比 gorm 要严谨得多,而代价则是啰嗦的指令式调用,极大损失了灵活性。

    与 ent 相比,同样使用代码生成的 node.js 的 prisma 是这么更新的:
    const bolg = await prisma.blog.update({
    where: {
    url: "[email protected]",
    },
    data: {
    url: "Viola the Magnificent",
    title: "The Last Theorem",
    author: "Clarke",
    },
    });
    prisma 将查询参数和更新数据全都赛进 update() 中,更容易实现动态参数。
    gitrebase
        15
    gitrebase  
       2023-11-23 12:43:30 +08:00
    #6 GPT 说的没错,MyBatis 纯纯的 Data Mapping ,跟 Object Relation Mapping 扯不上一点关系

    MyBatis 跟 Go 生态里的 sqlx 、squirrel 这种 SQL builder 是差不多的

    BTW ,Java 和 Go 里感觉没有一个 ORM 用起来是真的舒服的,他们对“网上说的‘复杂的场景’”都比较乏力,因此个人认为在 SQL 没有特别复杂的情况下(感觉没有太多表的 Join 就不算太复杂)直接用 JPA 、GORM 之类的完全没问题(绝大多数项目都到不了这程度)
    tunzao
        16
    tunzao  
       2023-11-23 12:44:19 +08:00
    是不是,又有什么关系呢?
    nothingistrue
        17
    nothingistrue  
       2023-11-23 13:57:13 +08:00   ❤️ 1
    @XCFOX #10 你所举例的代码中,EF Core 才是 ORM ,因为它的操作方法上完全看不出 SQL 的影子。GORM 还有后面的 ent 并不是 ORM ,因为它们的 Where()、Update()、SetXXX() 等方法,只不过是 SQL 的翻版,他们的数据模型基础还是关系模型。

    ORM 的全称是 Object Relational Mapping ,是对象数据模型跟关系数据模型之间的映射,它的重点是让你不必跳出面向对象开发的思路,就能使用关系数据库作为数据持久层。并不是简简单单的隐藏 SQL 。
    cheng6563
        18
    cheng6563  
       2023-11-23 14:11:20 +08:00   ❤️ 1
    严格的 ORM 不会让你碰到 SQL 。
    并且静态语言上的 ORM 框架还应当具备语法检查,这点就 C#做的比较好,Java 的 Jinq 只能凑合用。其他的 ORM 框架或多或少都还是要涉及手动拼接 SQL

    MyBatis 对数据库所有操作都要自己写 SQL ,他只是提供了个对 JDBC 优化的模板引擎,算不上 ORM
    另外,直接在程序里嵌 SQL 的都是大便框架,尤其是那些自创 DSL 来隐藏 SQL 细节的框架
    gitrebase
        19
    gitrebase  
       2023-11-23 14:17:31 +08:00
    @cheng6563 #18 哈哈哈哈最近刚看到有个 typescript 到 orm 框架说自己是 modern ORM ,但一看 README 它自己定义了一个 DSL 后我就直接懒得看了
    lolizeppelin
        20
    lolizeppelin  
       2023-11-23 14:38:42 +08:00
    @XCFOX
    ent 已经够好了起码可以定义简单的连表关系了

    静态语言没法做那么灵活的
    zhazi
        21
    zhazi  
       2023-11-23 15:06:00 +08:00
    虚空打靶呢?
    @burymme11
    shyangs
        22
    shyangs  
       2023-11-23 15:42:37 +08:00
    @burymme11
    @totoro52

    XML 沒有 Java 語法級別的提示和靜態語言重構輔助.

    新增欄位?就搜尋關鍵字然後一行一行改 XML 吧,一不小心就改錯了或漏了.(我相信任何用過 MyBatis 的人都遇到過這個問題)
    thinkershare
        23
    thinkershare  
       2023-11-23 15:55:21 +08:00
    你如果.NET 的 ORM 框架,立马就能理解 ORM 和各种 SQL Helper 的差别。同意楼上的,自定义 DSL 的都是狗屎。
    songteng0604
        24
    songteng0604  
       2023-11-23 18:32:40 +08:00
    //来自 B 站尚硅谷 SSM 课程 https://www.bilibili.com/video/BV1AP411s7D7?p=98

    ORM ( Object-Relational Mapping ,对象-关系映射)是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射,最后我们就可以通过方法调用进行数据库操作!!

    mybatis 是半自动 orm 思维的持久层框架(提供 crud 的方法,不提供 sql 语句),hibernate 是全自动 orm 框架(数据库数据和 Java 实体类的映射可以通过配置直接实现,最终提供 crud 的方法和自动生成对应的 sql 语句),但 hibernate 被淘汰了。

    将来开发中使用的是 mybatis-plus 。它是从半自动到全自动的过度,提供了单表 curd 的方法。
    ZZ74
        25
    ZZ74  
       2023-11-23 18:43:52 +08:00
    作为一个 CURDer ,你永远不知道查询条件会有多奇葩,所以我选择 ibatis 这类,碰到复杂能手写 sql ,简单还高效。简单场景 写过的几乎都能复用。
    tzengshinfu
        26
    tzengshinfu  
       2023-11-23 18:58:28 +08:00
    gowk
        27
    gowk  
       2023-11-23 19:02:52 +08:00
    DSL 纯粹是多此一举,失去了 SQL 的灵活,又增加了认知负担,得不偿失,SQL builder 或者 ORM 专注自己的领域就好了,do one thing and do it well ,Mybatis 真的就是一个 Mapper 而已,用起来还不错,就是业务逻辑复杂改起来就很啰嗦,Gorm ent 之流也能凑合用,但是都没有 EF ,Active Record ,Eloquent ,还有 node 世界的某些好用。真的感慨 Java 世界竟然没有一个顺手的 ORM ,JPA 太重,不灵活,也可能是我菜,所以干脆连笨重啰嗦的 Java 一并抛弃,拥抱 .NET ,EF 自不必说,甚至连国产的 SqlSugar 都可圈可点,用起来很舒服。

    查询语法:
    var exp = Expressionable.Create<Supplier, SysUser>();
    exp.AndIF(dto.SupName.IsNotEmpty(), (t, u) => t.SupName.Contains(dto.SupName));
    exp.AndIF(dto.CreditCode.IsNotEmpty(), (t, u) => t.CreditCode.Contains(dto.CreditCode));
    exp.AndIF(dto.Address.IsNotEmpty(), (t, u) => t.Address.Contains(dto.Address));
    exp.AndIF(dto.DetailAdmissionType.IsNotEmpty(), (t, u) => t.DetailAdmissionType.Contains(dto.DetailAdmissionType));
    exp.AndIF(dto.Leader.IsNotEmpty(), (t, u) => t.Leader.Contains(dto.Leader));
    exp.AndIF(dto.AdmissionTerm.HasValue, (t, u) => (int)t.AdmissionTerm == dto.AdmissionTerm);
    exp.AndIF(dto.StartNumber.HasValue, (t, u) => t.RegCapitalSubscribed >= dto.StartNumber);
    exp.AndIF(dto.EndNumber.HasValue, (t, u) => t.RegCapitalSubscribed <= dto.EndNumber);
    exp.AndIF(dto.DeptId.HasValue, (t, u) => u.DeptId == dto.DeptId);
    exp.AndIF(dto.AdmissionType.HasValue, (t, u) => t.AdmissionType == dto.AdmissionType);
    exp.AndIF(dto.CompanyType.HasValue, (t, u) => t.CompanyType == dto.CompanyType);
    exp.AndIF(dto.BeginTime.HasValue, (t, u) => t.CreateTime >= dto.BeginTime);
    exp.AndIF(dto.EndTime.HasValue, (t, u) => t.CreateTime <= dto.EndTime);

    var result = _supplierService.Queryable()
    .InnerJoin<SysUser>((t, u) => t.CreateBy == u.UserId)
    .InnerJoin<SysDept>((t, u, d) => u.DeptId == d.DeptId)
    .LeftJoin<SupplierInvoice>((t, u, d, si) => t.Id == si.SupId)
    .LeftJoin<SupplierChange>((t, u, d, si, ch) => t.Id == ch.SupId && ch.MostRecent)
    .Where(exp.ToExpression())
    .OrderByDescending(t => t.Id)
    .Select((t, u, d, si, ch) => new SupplierVo
    {
    Id = t.Id.SelectAll(),
    DeptName = d.DeptName,
    NickName = u.NickName,
    InvoiceStatus = si.Status,
    ChangeStatus = ch.Status,
    })
    .ToPage(dto);

    int count = DB.Queryable<T>().ClearFilter()
    .InnerJoin<SysUser>((table, usr) => table.CreateBy == usr.UserId)
    .InnerJoin<SysDept>((table, usr, dept) => usr.DeptId == dept.DeptId)
    .Where(table => table.Id == Record.TableId)
    .WhereIF(transition.Condition.IsNotEmpty(), transition.Condition, parameters)
    .Count();

    根据指定条件更新指定列:
    Update(new SysUser(){ Status = 1 }, it => new { it.Status }, f => f.Userid == 1));
    Update(w => w.NoticeId == model.NoticeId, it => new SysNotice(){ Update_time = DateTime.Now, Title = "通知标题" });

    另外还有不计其数的 CRUD 重载方法,覆盖了全部使用场景,开发效率很高
    dengbojing
        28
    dengbojing  
       2023-11-23 19:30:22 +08:00 via Android
    之前外包给移动做项目,是个二手项目接过来,接手给的 ibatis 加 pg ,我们就改改功能准备上了,结果移动是 oracle ,换个连接串跑起来,有些 sql 执行报错,直接被骂的狗血淋头,后面回来想了想换成了 hibernate ,然后公司跑 pg ,线上跑 oracle
    BiChengfei
        29
    BiChengfei  
       2023-11-23 19:40:57 +08:00
    当然不是,mybatis 只是一个 Jdbc 工具类
    totoro52
        30
    totoro52  
       2023-11-23 21:17:35 +08:00
    @shyangs idea 装个插件就能识别 而且可以属性跳转,属性不存在也会爆红, 并且支持生成简单的 crud 代码
    mangojiji
        31
    mangojiji  
    OP
       2023-11-24 01:52:10 +08:00
    @nothingistrue 我还是不能理解,Mybatis 也实现了比较基础的对象数据模型到关系数据模型的映射对吧。

    为什么 Mybatis 不算是,在实现了哪些"缺失的功能"之后,它才能真正算是 ORM ?
    mangojiji
        32
    mangojiji  
    OP
       2023-11-24 01:55:26 +08:00
    若仅仅是要不要手写 SQL 的差别,Mybatis 也有一些能够自动动态生成 SQL 的组件我记得。。。以及 queryWrapper 之类的东西,也能够避免编写 sql 呀(甚至不需要一个用于 mapper 的 xml 文件),它为啥就不是 ORM ?
    WDATM33
        33
    WDATM33  
       2023-11-24 09:20:28 +08:00
    做报表查询还得手写 sql ,一次查询非日结表少则关联 3 ,4 张表,多的甚至能关联十几张表,里面又是临时表又是一堆子查询。经常是一个 sql 能写出几百行,这种感觉不手写 sql 更头疼
    burymme11
        34
    burymme11  
       2023-11-24 15:51:16 +08:00
    @zhazi 我回复的 7 楼。漏了 @
    burymme11
        35
    burymme11  
       2023-11-24 15:57:56 +08:00
    @shyangs 如果硬要在 xml 中写 SQL ,idea 有 mybatis 插件,有一些语法提示和自动填充,建议在外部写好,比如 datagrip 或者 navicate 等专业的 SQL IDE 中写好,再贴到 XML 中。
    项目中,复杂 SQL 的占比不会很多,一般的业务查选,基于 BaseMapper 的接口就够用了,手写 SQL 的次数不多。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   949 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 21:29 · PVG 05:29 · LAX 13:29 · JFK 16:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.