参考资料:
运行原理:(四)Mybatis持久化框架原理之运行源码流程_mybatis持久化过程-优快云博客
Mybatis官网:https://mybatis.org/mybatis-3/zh/index.html
1. ORM
ORM(Object Relational Mapping)就是对象关系匹配,是为了解决面向对象与关系数据库存在的互不匹配的问题。简单来说,就是把关系数据库中的数据转换成面向对象程序中的对象。
常用的ORM框架有Hibernate和MyBatis,也就是ssh组合和ssm组合中的h与m。
它们的特点和区别如下:
- Hibernate对数据库结构提供了完整的封装,实现了POJO对象与数据库表之间的映射,能够自动生成并执行SQL语句。只要定义了POJO 到数据库表的映射关系,就可以通过Hibernate提供的方法完成数据库操作。Hibernate符合JPA规范,就是Java持久层API。
- Mybatis通过映射配置文件,将SQL所需的参数和返回的结果字段映射到指定对象,mybatis不会自动生成sql,需要自己定义sql语句,不过更方便对sql语句进行优化。
总结起来:
1、Hibernate配置要比Mybatis复杂的多,学习成本也比Mybatis高。Mybatis,简单、高效、灵活,但是需要自己维护sql;
2、Hibernate功能强大、全自动、适配不同数据库,但是非常复杂,灵活性稍差。
2. 概念
- MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。
- MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。
3. Java实体类
实体类按照如下规则和数据库表进行转换,注解全部是JPA中的注解:
- 表名默认使用类名,驼峰转下划线(只对大写字母进行处理),如UserInfo默认对应的表名为user_info。也可以使用@Table(name = "tableName")进行指定。
- 字段默认为实体类对象的Field名字驼峰转下划线形式,也可以使用@Column(name = "fieldName")指定字段名。
- 使用@Transient注解可以忽略字段,添加该注解的字段不会作为表字段使用.
- 建议一定是有一个@Id注解作为主键的字段,可以有多个@Id注解的字段作为联合主键。默认情况下,实体类中如果不存在包含@Id注解的字段,所有的字段都会作为主键字段进行使用(这种效率极低).
- 由于基本类型,如int作为实体类字段时会有默认值0,而且无法消除,所以实体类中建议不要使用基本类型。
- @NameStyle注解,用来配置对象名/字段和表名/字段之间的转换方式,该注解优先于全局配置style,可选值:
normal: 使用实体类名/属性名作为表名/字段名
camelhump: 这是默认值,驼峰转换为下划线形式
uppercase: 转换为大写
lowercase: 转换为小写
字段与实体类属性匹配
4. #{} 和 ${} 的区别总结
1、定义不同:#{} 预处理:而 ${} 是直接替换
2、使用不同:#{} 适用于所有类型的参数匹配;但 ${} 只适用于数值类型。
3、安全性不同:#{} 性能高,并且没有安全问题;但 $ {} 存在 SQL 注入的安全问题。
4、使用场景不同:
当传递的是一个 SQL 关键字 的时候,只能 使用 ${} 。
当传递的是一个字段,总之,就是需要获取到参数类型 与 内容,只能使用 #{}。
(PS:数字类型,#{} 和 ${} 都是可以使用的!)
5、 ${} 不能用于 模糊匹配查询;而 #{} 需要搭配 concat 才能在模糊匹配中使用。
5. resultType && resultMap
1、在对象属性名称 与 数据表字段名称,相同的情况下:
使用 resultType 比 resultMap 更爽!
2、在对象属性名称 与 数据表字段名称,不同的情况下:
使用 resultMap 可以指定 不同名称的 字段与属性 的映射关系。
PS:
association 标签,就是用来实现一对一情况的多表查询;
⼀对多需要使⽤ < collection > 标签,⽤法和 < association > 是一样的。
6. 动态SQL
< if >
choose、when、otherwise
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
trim
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
set
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
或者,可以通过使用trim元素来达到同样的效果:
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
7. 工作流程
最后总结一下mybatis与springBoot整合的整个流程步骤如下所示:
- 首先mybatis是通过MybatisAutoConfiguration自动配置的方式进行注入到spring中去的,在该类中同样注册了SqlSessionFactory以及SqlSessionTemplate。
- 构建SqlSessionFactory,主要是构建内部的Configuration属性,在这儿得到两个重要的参数。
- MappedStatement: 解析mapper.xml后封装成的对象。
- MapperRegistry类内的knownMappers缓存: key为namespace对应的dao的class,value为MapperProxyFactory。
- 通过@MapperScanner注解扫描所有的dao,将dao封装成MapperFactoryBean,后续通过getObject方法获取对应的MapperProxyFactory,以此创建对应的dao的代理类MapperProxy,在该代理类中封装了mapperInterface (是被代理类的class)和SqlSessionTemplate 两个重要属性。
- 执行sql,调用MapperProxy的invoke方法。
- 最终根据sql类型如select、insert、update、delete进入SqlSessionTemplate执行真正的sql。
- 在SqlSessionTemplate内部通过mapperInterface从SqlSessionFactory内的mappedStatements 属性缓存中获取对应的MappedStatement。进而执行相应的操作。