Mybatis入门

1、简介

在移动互联网时代,MyBatis 成为了目前互联网 Java 持久框架的首选。

MyBatis 本是 Apache 的一个开源项目——iBatis,2010 年这个项目由 Apache Software Foundation 迁移到了 Google Code,并且改名为 MyBatis。

MyBatis 是一个基于 Java 的持久层框架。MyBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAO),它消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。

MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。

Hibernate 和 MyBatis 的区别

1)sql 优化方面

Hibernate 不需要编写大量的 SQL,就可以完全映射,提供了日志、缓存、级联(级联比 MyBatis 强大)等特性,此外还提供 HQL(Hibernate Query Language)对 POJO 进行操作。但会多消耗性能。

MyBatis 手动编写 SQL,支持动态 SQL、处理列表、动态生成表名、支持存储过程。工作量相对大些。

2)开发方面

MyBatis 是一个半自动映射的框架,因为 MyBatis 需要手动匹配 POJO、SQL 和映射关系。

Hibernate 是一个全表映射的框架,只需提供 POJO 和映射关系即可。

3)Hibernate 优势

Hibernate 的 DAO 层开发比 MyBatis 简单,MyBatis  需要维护 SQL 和结果映射。

Hibernate 对对象的维护和缓存要比 MyBatis 好,对增删改查的对象的维护要方便。

Hibernate 数据库移植性很好,MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。

Hibernate 有更好的二级缓存机制,可以使用第三方缓存。MyBatis 本身提供的缓存机制不佳。

4)Mybatis优势

MyBatis 可以进行更为细致的 SQL 优化,可以减少查询字段。

MyBatis 容易掌握,而 Hibernate 门槛较高。

总的来说,MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架,Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。

所以对于性能要求不太苛刻的系统,比如管理系统、ERP 等推荐使用 Hibernate,而对于性能要求高、响应快、灵活的系统则推荐使用 MyBatis。

2、工作原理


mybatis 工作原理

1)读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。

2)加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

3)构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

4)创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。

5)Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

6)MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。

7)输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。

8)输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

3、核心组件

1)SqlSessionFactoryBuilder(构造器):它会根据配置或者代码来生成 SqlSessionFactory,采用的是分步构建的 Builder 模式。

2)SqlSessionFactory(工厂接口):依靠它来生成 SqlSession,使用的是工厂模式。

3)SqlSession(会话):一个既可以发送 SQL 执行返回结果,也可以获取 Mapper 的接口。在现有的技术中,一般我们会让其在业务逻辑代码中“消失”,而使用的是 MyBatis 提供的 SQL Mapper 接口编程技术,它能提高代码的可读性和可维护性。

4)SQL Mapper(映射器):MyBatis 新设计存在的组件,它由一个 Java 接口和 XML 文件(或注解)构成,需要给出对应的 SQL 和映射规则。它负责发送 SQL 去执行,并返回结果。

4、实现映射器的两种方式

映射器是 MyBatis 中最重要、最复杂的组件,它由一个接口和对应的 XML 文件(或注解)组成。它可以配置以下内容:

描述映射规则。

提供 SQL 语句,并可以配置 SQL 参数类型、返回类型、缓存刷新等信息。

配置缓存。

提供动态 SQL。

1、XML


mybatis XML

除 XML 方式定义映射器外,还可以采用注解方式定义映射器,它只需要一个接口就可以通过 MyBatis 的注解来注入 SQL


mybatis 注解

也许你会觉得使用注解的方式比 XML 方式要简单得多。如果它和 XML 方式同时定义时,XML 方式将覆盖掉注解方式,所以 MyBatis 官方推荐使用的是 XML 方式

复杂sql,如果放入 @Select 中会明显增加注解的内容。如果把大量的 SQL 放入 Java 代码中,显然代码的可读性也会下降。如果同时还要考虑使用动态 SQL,比如当参数 userName 为空,则不使用 u.user_name like concat('%',${userName},'%')作为查询条件;当 roleName 为空,则不使用 r.role_name like concat('%',${roleName},'%')作为查询条件,但是还需要加入其他的逻辑,这样就使得这个注解更加复杂了,不利于日后的维护和修改。

5、typeAlases

由于类的全限定名称很长,需要大量使用的时候,总写那么长的名称不方便。在 MyBatis 中允许定义一个简写来代表这个类,这就是别名,别名分为系统定义别名和自定义别名。

在 MyBatis 中别名由类 TypeAliasRegistry(org.apache.ibatis.type.TypeAliasRegistry)去定义。注意,在 MyBatis 中别名不区分大小写


系统别名

如果需要使用对应类型的数组型,要看其是否能支持数据,如果支持只需要使用别名加[]即可,比如 _int 数组的别名就是 _int[]。而类似 list 这样不支持数组的别名,则不能那么写。

自定义别名

由于现实中,特别是大型互联网系统中存在许多对象,比如用户(User)这个对象有时候需要大量重复地使用,因此 MyBatis 也提供了用户自定义别名的规则。我们可以通过 TypeAliasRegistry 类的 registerAlias 方法注册,也可以采用配置文件或者扫描方式来自定义它。

自定义别名

这样就可以定义一个别名了。如果有很多类需要定义别名,那么用这样的方式进行配置可就不那么轻松了。MyBatis 还支持扫描别名。比如上面的两个类都在包 com.mybatis.po 之下,那么就可以定义为:

包扫描

这样 MyBatis 将扫描这个包里面的类,将其第一个字母变为小写作为其别名,比如类 Role 的别名会变为 role,而 User 的别名会变为 user。使用这样的规则,有时候会出现重名。

比如 com.mybatis.po.User 这个类,MyBatis 还增加了对包 com.mybatis.po 的扫描,那么就会出现异常,这个时候可以使用 MyBatis 提供的注解 @Alias("user3")进行区分,如下所示。


别名注解

6、properties and settings

properties 属性可以给系统配置一些运行参数,可以放在 XML 文件或者 properties 文件中,而不是放在 Java 编码中,这样的好处在于方便参数修改,而不会引起代码的重新编译。一般而言,MyBatis 提供了 3 种方式让我们使用 properties,它们是:

property 子元素

mybatis properties xml

这里使用了元素 <properties> 下的子元素 <property> 定义,用字符串 database.username 定义数据库用户名,然后就可以在数据库定义中引入这个已经定义好的属性参数,如 ${database.username},这样定义一次就可以到处引用了。但是如果属性参数有成百上千个,显然使用这样的方式不是一个很好的选择,这个时候可以使用 properties 文件。

properties 文件

使用 properties 文件是比较普遍的方法,一方面这个文件十分简单,其逻辑就是键值对应,我们可以配置多个键值放在一个 properties 文件中,也可以把多个键值放到多个 properties 文件中,这些都是允许的,它方便日后维护和修改。

我们创建一个文件 jdbc.properties 放到 classpath 的路径下,如下所示,然后在 MyBatis 中通过 <properties> 的属性 resource 来引入 properties 文件。也可以按 ${database.username} 的方法引入 properties 文件的属性参数到 MyBatis 配置文件中。这个时候通过维护 properties 文件就可以维护我们的配置内容了。

程序代码传递

在真实的生产环境中,数据库的用户密码是对开发人员和其他人员保密的。运维人员为了保密,一般都需要把用户和密码经过加密成为密文后,配置到 properties 文件中。

对于开发人员及其他人员而言,就不知道其真实的用户密码了,数据库也不可能使用已经加密的字符串去连接,此时往往需要通过解密才能得到真实的用户和密码了。

现在假设系统已经为提供了这样的一个 CodeUtils.decode(str)进行解密,那么我们在创建 SqlSessionFactory 前,就需要把用户名和密码解密,然后把解密后的字符串重置到 properties 属性中

首先使用 Resources 对象读取了一个 jdbc.properties 配置文件,然后获取了它原来配置的用户和密码,进行解密并重置,最后使用 SqlSessionFactoryBuilder 的 build 方法,传递多个 properties 参数来完成。

这将覆盖之前配置的密文,这样就能连接数据库了,同时也满足了运维人员对数据库用户和密码安全的要求。

7、typeHandler

在 JDBC 中,需要在 PreparedStatement 对象中设置那些已经预编译过的 SQL 语句的参数。执行 SQL 后,会通过 ResultSet 对象获取得到数据库的数据,而这些 MyBatis 是根据数据的类型通过 typeHandler 来实现的。

在 typeHandler 中,分为 jdbcType 和 javaType,其中 jdbcType 用于定义数据库类型,而 javaType 用于定义 Java 类型,那么 typeHandler 的作用就是承担 jdbcType 和 javaType 之间的相互转换。

如图 1 所示。在很多情况下我们并不需要去配置 typeHandler、jdbcType、javaType,因为 MyBatis 会探测应该使用什么类型的 typeHandler 进行处理,但是有些场景无法探测到。


typeHandler作用

对于那些需要使用自定义枚举的场景,或者数据库使用特殊数据类型的场景,可以使用自定义的 typeHandler 去处理类型之间的转换问题。

和别名一样,在 MyBatis 中存在系统定义 typeHandler 和自定义 typeHandler。MyBatis 会根据 javaType 和数据库的 jdbcType 来决定采用哪个 typeHandler 处理这些转换规则。系统提供的 typeHandler 能覆盖大部分场景的要求,但是有些情况下是不够的,比如我们有特殊的转换规则,枚举类就是这样。

在大部分的场景下,MyBatis 的 typeHandler 就能应付一般的场景,但是有时候不够用。比如使用枚举的时候,枚举有特殊的转化规则,这个时候需要自定义 typeHandler 进行处理它。

系统定义的 typeHandler 可以知道,要实现 typeHandler 就需要去实现接口 typeHandler,或者继承 BaseTypeHandler(实际上,BaseTypeHandler 实现了 typeHandler 接口)。

8、mybatis 标签

select 属性


insert

MySQL、SQL Server 等数据库的表格可以采用自动递增的字段作为主键,有时可能需要使用这个刚刚产生的主键,用于关联其他业务。

自定义主键


update delete

另外条件标签包括:if、choose、when、otherwise

还有功能性标签:trim、where、set、foreach、bind

其中foreach用作批量操作

在进行模糊查询时,如果使用“${}”拼接字符串,则无法防止 SQL 注入问题。如果使用字符串拼接函数或连接符号,但不同数据库的拼接函数或连接符号不同。

例如 MySQL 的 concat 函数、Oracle 的连接符号“||”,这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。幸运的是,MyBatis 提供了 元素来解决这一问题。

在 myBatisDemo03 应用中测试 <bind> 元素,具体过程如下: 


bind标签

9、级联查询

<resultMap> 元素表示结果映射集,是 MyBatis 中最重要也是最强大的元素,主要用来定义映射规则、级联的更新以及定义类型转化器等。

resultMap

一条查询 SQL 语句执行后将返回结果,而结果可以使用 Map 存储,也可以使用 POJO 存储。


任何 select 语句都可以使用 Map 存储结果 

级联关系是一个数据库实体的概念,有 3 种级联关系,分别是一对一级联、一对多级联以及多对多级联。

级联的优点是获取关联数据十分方便,但是级联过多会增加数据库系统的复杂度,同时降低系统的性能。

在实际开发中要根据实际情况判断是否需要使用级联。更新和删除的级联关系很简单,由数据库内在机制即可完成。本节只讲述级联查询的相关实现。

如果表 A 中有一个外键引用了表 B 的主键,A 表就是子表,B 表就是父表。当查询表 A 的数据时,通过表 A 的外键将表 B 的相关记录返回,这就是级联查询。例如,当查询一个人的信息时,同时根据外键(身份证号)将他的身份证信息返回。

一对一级联关系在现实生活中是十分常见的,例如一个大学生只有一张一卡通,一张一卡通只属于一个学生。再如人与身份证的关系也是一对一的级联关系。

MyBatis 如何处理一对一级联查询呢?在 MyBatis 中,通过 <resultMap> 元素的子元素 <association> 处理这种一对一级联关系。

参考自: MyBatis动态sql之bind标签 (biancheng.net)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容