Mybatis 是⼀个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注
SQL 语句本⾝,不需要花费精⼒去处理加载驱动、创建连接、创建statement 等繁杂的过
程。程序员直接编写原⽣态 sql,可以严格控制 sql 执⾏性能,灵活度⾼。
MyBatis 可以使⽤ XML 或注解来配置和映射原⽣信息,将 POJO 映射成数据库中的记
录,避免了⼏乎所有的 JDBC 代码和⼿动设置参数以及获取结果集。
再说⼀下缺点
SQL语句的编写⼯作量较⼤,尤其当字段多、关联表多时,对开发⼈员编写SQL语句的功
底有⼀定要求
SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
为什么说Mybatis是半⾃动ORM映射⼯具?它与全⾃动的区别在哪⾥?
Hibernate属于全⾃动ORM映射⼯具,使⽤Hibernate查询关联对象或者关联集合对象时,
可以根据对象关系模型直接获取,所以它是全⾃动的。
⽽Mybatis在查询关联对象或关联集合对象时,需要⼿动编写SQL来完成,所以,被称之
为半⾃动ORM映射⼯具。
1、数据连接创建、释放频繁造成系统资源浪费从⽽影响系统性能
解决:在mybatis-config.xml中配置数据链接池,使⽤连接池统⼀管理数据库连接。
2、sql语句写在代码中造成代码不易维护
解决:将sql语句配置在XXXXmapper.xml⽂件中与java代码分离。
3、向sql语句传参数⿇烦,因为sql语句的where条件不⼀定,可能多也可能少,占位符需
要和参数⼀⼀对应。
解决: Mybatis⾃动将java对象映射⾄sql语句。
4、对结果集解析⿇烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库
记录封装成pojo对象解析⽐较⽅便。
解决:Mybatis⾃动将sql执⾏结果映射⾄java对象。
1、 创建SqlSessionFactory
可以从配置或者直接编码来创建SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
2、 通过SqlSessionFactory创建SqlSession
SqlSession(会话)可以理解为程序和数据库之间的桥梁
SqlSession session = sqlSessionFactory.openSession();
3、 通过sqlsession执⾏数据库操作
可以通过 SqlSession 实例来直接执⾏已映射的 SQL 语句:
Blog blog =
(Blog)session.selectOne("org.mybatis.example.BlogMapper.selectBlog",
101);
更常⽤的⽅式是先获取Mapper(映射),然后再执⾏SQL语句:
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
4、 调⽤session.commit()提交事务
如果是更新、删除语句,我们还需要提交⼀下事务。
5、 调⽤session.close()关闭会话
最后⼀定要记得关闭会话。
当然,万物皆可集成Spring,MyBatis通常也是和Spring集成使⽤,Spring可以帮助我们创建线
程安全的、基于事务的 SqlSession 和映射器,并将它们直接注⼊到我们的 bean 中,我们不需
要关⼼它们的创建过程和⽣命周期,那就是另外的故事了。
第⼀种⽅法:使⽤foreach标签
foreach的主要⽤在构建in条件中,它可以在SQL语句中进⾏迭代⼀个集合。foreach标签的属性
主要有item,index,collection,open,separator,close。
item 表⽰集合中每⼀个元素进⾏迭代时的别名,随便起的变量名;
index 指定⼀个名字,⽤于表⽰在迭代过程中,每次迭代到的位置,不常⽤;
open 表⽰该语句以什么开始,常⽤“(”;
separator 表⽰在每次进⾏迭代之间以什么符号作为分隔符,常⽤“,”;
close 表⽰以什么结束,常⽤“)”。
在使⽤foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,
但是在不同情况下,该属性的值是不⼀样的,主要有以下3种情况:
1. 如果传⼊的是单参数且参数类型是⼀个List的时候,collection属性值为list
2. 如果传⼊的是单参数且参数类型是⼀个array数组的时候,collection的属性值为array
3. 如果传⼊的参数是多个的时候,我们就需要把它们封装成⼀个Map了,当然单参数也可以
封装成map,实际上如果你在传⼊参数的时候,在MyBatis⾥⾯也是会把它封装成⼀个Map
的,
map的key就是参数名,所以这个时候collection属性值就是传⼊的List或array对象在⾃⼰封
装的map⾥⾯的key
获取配置
获取配置这⼀步经过了⼏步转化,最终由⽣成了⼀个配置类Configuration实例,这个配置
类实例⾮常重要,主要作⽤包括:
读取配置⽂件,包括基础配置⽂件和映射⽂件
初始化基础配置,⽐如MyBatis的别名,还有其它的⼀些重要的类对象,像插件、映射
器、ObjectFactory等等
提供⼀个单例,作为会话⼯⼚构建的重要参数
它的构建过程也会初始化⼀些环境变量,⽐如数据源
会话运⾏
会话运⾏是MyBatis最复杂的部分,它的运⾏离不开四⼤组件的配合:
1. 读取 MyBatis 配置⽂件——mybatis-config.xml 、加载映射⽂件——映射⽂件即 SQL 映射
⽂件,⽂件中配置了操作数据库的 SQL 语句。最后⽣成⼀个配置对象。
2. 构造会话⼯⼚:通过 MyBatis 的环境等配置信息构建会话⼯⼚ SqlSessionFactory。
3. 创建会话对象:由会话⼯⼚创建 SqlSession 对象,该对象中包含了执⾏ SQL 语句的所有
⽅法。
4. Executor 执⾏器:MyBatis 底层定义了⼀个 Executor 接⼜来操作数据库,它将根据
SqlSession 传递的参数动态地⽣成需要执⾏的 SQL 语句,同时负责查询缓存的维护。
5. StatementHandler:数据库会话器,串联起参数映射的处理和运⾏结果映射的处理。
6. 参数处理:对输⼊参数的类型进⾏处理,并预编译。
7. 结果处理:对返回结果的类型进⾏处理,根据对象映射规则,返回相应的对象。
我们⼀般把Mybatis的功能架构分为三层:
API接⼜层:提供给外部使⽤的接⼜API,开发⼈员通过这些本地API来操纵数据库。接⼜
层⼀接收到调⽤请求就会调⽤数据处理层来完成具体的数据处理。
数据处理层:负责具体的SQL查找、SQL解析、SQL执⾏和执⾏结果映射处理等。它主要
的⽬的是根据调⽤的请求完成⼀次数据库操作。
基础⽀撑层:负责最基础的功能⽀撑,包括连接管理、事务管理、配置加载和缓存处理,
这些都是共⽤的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基
础的⽀撑。
如何编写⼀个插件?
我们⾃⼰编写MyBatis 插件,只需要实现拦截器接⼜ Interceptor (org.apache.ibatis. plugin
Interceptor ),在实现类中对拦截对象和⽅法进⾏处理。
实现Mybatis的Interceptor接⼜并重写intercept()⽅法
这⾥我们只是在⽬标对象执⾏⽬标⽅法的前后进⾏了打印;
public class MyInterceptor implements Interceptor {
Properties props=null;
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("before……");
//如果当前代理的是⼀个⾮代理对象,那么就会调⽤真实拦截对象的⽅法
// 如果不是它就会调⽤下个插件代理对象的invoke⽅法
Object obj=invocation.proceed();
System.out.println("after……");
return obj;
}
}
然后再给插件编写注解,确定要拦截的对象,要拦截的⽅法
@Intercepts({@Signature(
type = Executor.class, //确定要拦截的对象
method = "update", //确定要拦截的⽅法
args = {MappedStatement.class,Object.class} //拦截⽅法的参数
)})
public class MyInterceptor implements Interceptor {
Properties props=null;
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("before……");
//如果当前代理的是⼀个⾮代理对象,那么就会调⽤真实拦截对象的⽅法
// 如果不是它就会调⽤下个插件代理对象的invoke⽅法
Object obj=invocation.proceed();
System.out.println("after……");
return obj;
}
}
20.MyBatis是如何进⾏分页的?分页插件的原理是什么?
MyBatis是如何分页的?
MyBatis使⽤RowBounds对象进⾏分页,它是针对ResultSet结果集执⾏的内存分页,⽽⾮物理
分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使⽤分页插件
来完成物理分页。
分页插件的原理是什么?
分页插件的基本原理是使⽤Mybatis提供的插件接⼜,实现⾃定义插件,拦截Executor的
query⽅法
在执⾏查询的时候,拦截待执⾏的sql,然后重写sql,根据dialect⽅⾔,添加对应的物理分
页语句和物理分页参数。
举例:select * from student,拦截sql后重写为:select t.* from (select * from student) t limit
0, 10
可以看⼀下⼀个⼤概的MyBatis通⽤分页拦截器: