文章目录
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 门槛较高。
0. pom.xml
<!-- mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!-- DAO -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
1. MyBatis工作流程
1.1 核心接口概览
SqlSessionFactoryBuilder
(构造器):它会根据配置或者代码来生成SqlSessionFactory
,采用的是分步构建的 Builder 模式。SqlSessionFactory
(工厂接口):依靠它来生成SqlSession
,使用的是工厂模式。SqlSession
(会话):一个既可以发送 SQL 执行返回结果,也可以获取 Mapper 的接口。在现有的技术中,一般我们会让其在业务逻辑代码中“消失”,而使用的是 MyBatis 提供的 SQL Mapper 接口编程技术,它能提高代码的可读性和可维护性。其功能主要有:获取 Mapper 接口、发送 SQL 给数据库、控制数据库事务。SQL Mapper
(映射器):MyBatis 新设计存在的组件,它由一个 Java 接口和 XML 文件(或注解)构成,需要给出对应的 SQL 和映射规则。它负责发送 SQL 去执行,并返回结果。
2. 完成ORM映射
MyBatis是一个半自动ORM框架,需要手动完成DAO层的操作。
主要分为两部分:
- POJO类映射(正常情况下会自动完成)。
- DAO层接口映映射(需要手动完成)。
2.1 POJO类映射
构建一个Java POJO类 Teacher
:
@Data // 构造函数和set/get方法并不是必须的,MyBatis使用反射注入
public class Teacher {
private Integer id;
private String name;
private Integer age;
private String email;
}
为该类添加映射 TeacherMapper.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pers.model.domain.TeacherMapper">
<!-- Java 属性到数据库的映射方式 -->
<resultMap type="pers.model.domain.Teacher" id="TeacherBeanMapper">
<!-- id 标签:映射主键属性
result 标签:映射非主键属性
property 属性:实体的属性名
column 属性:数据库表的字段名 -->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
</resultMap>
</mapper>
- 默认情况下,这种映射方式会被自动完成,例如Java中字段为
myName
的属性会被自动映射到数据库表中的my_name
的字段列(类名不会被映射到表名)。
之后,需要把该映射配置文件写入mybatis-config.xml
:
<!-- 将mapper文件加入到配置文件中 -->
<mappers>
<mapper resource="pers/model/domain/TeacherMapper.xml"/>
</mappers>
2.1.1 标签:resultMap
元素表示结果映射集,主要用来定义映射规则、级联的更新以及定义类型转化器等。该标签结构如下:
<resultMap id="" type="">
<constructor> <!-- 类再实例化时用来注入结果到构造方法 -->
<idArg/> <!-- ID参数,结果为ID -->
<arg/> <!-- 注入到构造方法的一个普通结果 -->
</constructor>
<id/> <!-- 用于表示哪个列是主键 -->
<result/> <!-- 注入到字段或JavaBean属性的普通映射结果 -->
<association property=""/> <!-- 用于一对一关联 -->
<collection property=""/> <!-- 用于一对多、多对多关联 -->
<discriminator javaType=""> <!-- 使用结果值来决定使用哪个结果映射 -->
<case value=""/> <!-- 基于某些值的结果映射 -->
</discriminator>
</resultMap>
其中, <association>
等标签将会在在第6小节中进行讲解。
2.2 使用配置文件构建映射器接口(映射器)
2.2.1 (显式)定义Java接口类完成接口映射
定义一个Java类 pers.model.domain.TeacherMapper
:
public interface TeacherMapper {
Teacher getById(Long id);
}
显式定义以上接口,并编写相应的TeacherMapper.xml
文件,通过MyBatis的动态代理完成接口方法:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pers.model.domain.TeacherMapper"> <!-- 显式定义的Java接口地址 -->
<!-- 通过注入完成定义
parameterType :输入的参数类型;若有多个详见下文
resultType :Java中的类,作为返回类型 -->
<select id="getById" parameterType="java.lang.Long" resultType="pers.model.domain.Teacher">
SELECT * FROM teacher WHERE id = #{id}
</select>
</mapper>
测试:
// 获取一个Mapper类,代码可读性较好
System.out.println(sqlSession.getMapper(TeacherMapper.class).getById(1L));
2.2.2 (隐式)自动完成接口映射
也可以直接将定义 pers.model.domain.TeacherMapper.java
Java接口类的步骤省去(但不推荐),如直接定义xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pers.model.domain.TeacherMapper"> <!-- 隐式定义时Java接口类不一定存在,会由MyBatis动态代理创建 -->
<!-- 隐式定义的 -->
<select id="getAllTeacher" resultType="pers.model.domain.Teacher"> SELECT * FROM teacher; </select>
<!-- 显示定义的 -->
<select id="getById" parameterType="java.lang.Long" resultType="pers.model.domain.Teacher">
SELECT * FROM teacher WHERE id = #{id} OR name = #{name}
</select>
</mapper>
测试:
sqlSession.selectList("pers.model.domain.TeacherMapper.getAllTeacher").forEach(System.out::println);
2.3.3 使用注解构建映射器接口(不推荐)
也可以使用接口完成映射器,但由于其完成动态SQL、复杂SQL等,会显式增加代码的阅读复杂度,不被推荐使用。使用示例:
public interface TeacherMapper {
@Select