概述
- MyBatis是apache的一个开源项目iBatis,2010年改名为MyBatis,2013年11月迁移到Github
- MyBatis是一款优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
- Mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回
- MyBatis支持自定义SQL、存储过程以及高级映射
执行流程原理
- 读取MyBatis的配置文件: mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息
- 加载映射文件: 映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表
- 构造会话工厂: 通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory
- 创建会话对象: 由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法
- Executor执行器: MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护
- MappedStatement对象: 在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息
- 输入参数映射: 输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程
- 输出结果映射: 输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程
SQL映射文件(开发中关注的核心)
可参考官网:mybatis – MyBatis 3 | XML 映射器
MyBatis分页插件PageHelper
导入Maven依赖包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<!--pageHelper使用了springboot的自动装配功能,
springboot启动时自动装配pageHelper相关的bean,所以在开发时无需手动添加任何注解,
spring.factories文件配置了自动配置类,Springboot启动时自动加载该对象到容器中 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
<version>${pagehelper-spring-boot-autoconfigure.version}</version>
</dependency>
<!--pagehelper-spring-boot-starter启动包,
该包通过spring.provides配置文件把需要依赖的相关Jar包导入的工程中。
因此在springboot工程中只需要把pagehelper-spring-boot-starter引入即可,相关Jar包会自动导入
provides内容: pagehelper-spring-boot-autoconfigure,pagehelper,mybatis-spring-boot-autoconfigure,mybatis,mybatis-spring;
实际上这个启动包非必要的,可要直接引入相关的jar即可
-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-spring-boot-starter.version}</version>
</dependency>
启用分页(PageHelper会自动拼接sql查询数据)
核心类就是PageHelper和PageInfo
PageHelper.startPage(pageNum,pageSize);//设置分页属性pageNum(第几页)和pageSize(每页显示的条数)
List<Users> list = userMapper.getUserList();//查询总数
PageInfo<Users> pageInfo = new PageInfo<>(list);//把查询到的结果封装到PageInfo类中
SpringBoot整合MyBatis
可参考该博文:Spring Boot 整合 Mybatis 实践教程(干货) - 知乎 (zhihu.com)[目前公司微服务应用整合Mybatis过程和该博文介绍基本一致]
其他
JDBC VS MyBatis
传统方式JDBC访问数据库特点
- 使用JDBC访问数据库有大量重复代码(如注册驱动、获取连接、获取传输器、释放资源等)
- JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低
- SQL是写死在程序中,一旦修改SQL,需要对类重新编译
- 对查询SQL执行后返回的ResultSet对象,需要手动处,有时会特别麻烦
mybatis框架访问数据库的特点
- Mybatis对JDBC对了封装,可以简化JDBC代码
- Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率
- Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译
- 对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象
- JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等)在Mybatis框架中几乎都得到了解决
Hibernate VS MyBatis
- ORM指的是对象关系映射,是一种持久化技术,将面向对象程序中的对象持久化到数据库中的技术; Hibernate和Mybatis属于ORM框架
- Hibernate比较复杂、庞大,学习周期较长; Mybatis主要依赖于sql的书写,让开发者感觉更熟悉
- Hibernate与数据库具体的关联都在XML中,适用于不同的数据库; Mybatis依赖数据库编写SQL,所以扩展性、迁移性比较差
- 如果直接操作数据库表,没有过多的定制,建议使用Hibernate方式; 如果要灵活使用SQL语句,建议采用MyBatis方式
业务批量操作最佳实践
批量新增
<insert id="batchSave" parameterType="java.util.List">
insert into User(title,content) values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.title},#{item.content})
</foreach>
</insert>
<!-- 参数类型是List<User>,实体集合 -->
- MyBatis利用For循环批量插入: 一万条数据总耗时:26348ms
- MyBatis以集合方式(xml中采用<foreach>)批量新增(推荐): 一万条数据总耗时:521ms
- MyBatis-Plus提供的SaveBatch方法: 一万条数据总耗时:24674ms,该问题解决方案可以在数据库配置的uri后面加上该属性后启用批量更新语句的优化rewriteBatchedStatements=true,可以将耗时降低为500ms
批量更新
<update id="batchUpdate" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update User
<set>
title = #{item.title}, content = #{item.content}
</set>
where id = #{item.id}
</foreach>
</update>
<!-- 参数类型是List<User>,实体集合 -->
批量删除
<delete id="batchDel" parameterType="java.util.List">
delete from User where id in
<foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</delete>
<!-- 参数类型是List<String>,id集合 -->