一.什么是Mybatis?
MyBatis是一个开源的数据持久层框架,它内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis作为持久层框架,其主要思想是将程序中大量SQL语句剥离出来,配置在配置文件中,实现SQL的灵活配置。这样做的好处是将SQL与程序代码分离,可以在不修改程序代码的情况下,直接在配置文件中修改SQL。Mybatis通过简单的XML或者注解进行配置和原始映射,将POJO实体类和SQL语句之间建立映射关系,是一种半自动化的ORM实现。
二.Mybatis的优点?
1)与JDBC相比,减少了50%以上的代码量。
2)MyBatis是最简单的持久化框架,小巧并且简单易学。
3)MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用。
4)提供XML标签,支持编写动态SQL语句。
5)提供映射标签,支持对象与数据库的ORM字段关系映射。
三.Mybatis框架的组成(重点!!!)
四.Mybatis框架的工作流程(重点!!!)
1、读取Mybatis配置文件
2、根据读取到的配置文件生成SqlSessionFactoryBuilder和接口的实现类,创建 SqlSessionFactory
3、创建SqlSession对象(开启事务)
4、操作目标数据库
5、提交事务
6、关闭SqlSession
五.面试题:
1.#{}和${}的区别是什么?
#{}
是预编译处理,${}
是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}
替换为?号,调用PreparedStatement的set方法来赋值,会自动添加引号;
Mybatis在处理
时
,
就
把
{}时,就把
时,就把{}替换成变量的值,参数需要手动加引号。
使用#{}可以有效的防止SQL注入,提高系统安全性。
2.当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
- 给查询出的列命名别名,别名和属性名一致
- 设置resultMap(一对一和一对多)
3.模糊查询like语句该怎么写?
- 1).在SQL语句中拼接 %
userName like CONCAT('%',#{},'%')
- 2).在传递的实参中,参数值的两侧%
4.通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
工作原理:接口+mapper映射文件结合起来,生成实现类,然后通过反射创建实现类的对象,通过这个对象去调用方法
-
Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。
-
不能重载.Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个
<select>
、<insert>
、<update>
、<delete>
标签,都会被解析为一个MapperStatement对象。
5.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
-
第一种是使用
<resultMap>
标签,逐一定义数据库列名和对象属性名之间的映射关系。 -
第二种是将列名和属性名一一对应.
如果不一致,使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
6.如何执行批量插入?
重点在这一句:
sqlsessionfactory.opensession(executortype.batch)
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) {
mapper.insertname(name);
}
sqlsession.commit();
} finally {
sqlsession.close();
}
7.在mapper中如何传递多个参数?
- 赋值给一个对象
- 存入Map集合中
- @Param注解
8.Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
- 1)Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。
- 2)Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
- 3)原理:先解析方法的参数列表,然后根据参数的值动态生成sql,执行sql语句后,做结果映射
9.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不能重复. 如果配置了namespace:那么id可以重复
namespace不是必须的,如果没有配置,mybatis把所有没有namespace的XML文件编译成一个文件
所以id是不能重复的。
区分原理:namespace.id值作为HashMap集合的key值
10.mybatis的核心类是什么?
SqlSessionFactoryBuilder
读取全局配置文件,得到数据源信息,创建连接工厂SqlSessionFactory。它的特点是,当创建了SqlSessionFactory对象之后,这个类就不需要了。因此,它的最佳范围是存在于方法体内,也就是局部变量。
SqlSessionFactory
连接工厂;创建SqlSession实例的工厂。它的特点是,SqlSessionFactory对象一旦被创建,就无法销毁或者再创建,也不建议多次创建SqlSessionFactory对象。因此,它的最佳范围是应用(Application)范围内。
SqlSession
会话对象类,SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。SqlSession对应着一次数据库会话,所以每次访问数据库时都需要在SqlSessionFactory
实例的openSession()
方法中创建它。但一个SqlSession会话也可以执行多次SQL语句。 SqlSession关闭后消失
Mapper
映射类,跟映射关系对应,是从SqlSession中获取的。任何映射器实例的最大作用域是和请求它们的 SqlSession 相同的。尽管如此,映射器实例的最佳作用域是方法作用域。也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例,尽管在整个请求作用域(request scope)保持映射器实例也不会有什么问题,但是很快你会发现,像 SqlSession 一样,在这个作用域上管理太多的资源的话会难于控制。所以要保持简单,最好把映射器放在方法作用域(method scope)内。
11.Mybatis都有哪些Executor执行器?他们之间的区别是什么?
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ResourceExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
12.Mybatis中接口绑定有几种实现方式?怎么实现的?
接口绑定有两种实现方式,
- 一种是通过注解绑定,就是在接口的方法上面加上 @Select@Update等注解里面包含Sql语句来绑定,
- 另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名.
13.传入的参数是数组或集合,如何使用动态SQL进行遍历?
需要使用迭代标签foreach遍历
UserDao.java
//参数是数组类型
public List<User> getAllUsersByAry(int[] aryRole);
//参数是集合类型
public List<User> getAllUsersByList(List<Integer> roleList);
UserMapper.xml
<!-- 参数是数组类型 -->
<select id="getAllUsersByAry" resultType="User">
select id,userCode,userName,userPassword,userRole
from smbms_user
where userRole in
<!-- 需要使用迭代标签遍历数组
array:关键字,参数是数组,即遍历的是数组
-->
<foreach collection="array" item="aryRole"
open="(" close=")" separator=",">
#{aryRole}
</foreach>
</select>
<!-- 参数是集合类型 -->
<select id="getAllUsersByList" resultType="User">
select id,userCode,userName,userPassword,userRole
from smbms_user
where userRole in
<!-- 需要使用迭代标签遍历集合
list:关键字,参数是集合,即遍历的是集合
-->
<foreach collection="list" item="roleList"
open="(" close=")" separator=",">
#{roleList}
</foreach>
</select>
14.mybatis注解方式是怎样通过没有实现类的dao接口进行数据库操作?
mybatis注解方式通过没有实现类的dao接口进行数据库操作的原理,一句话概括,就是jdk proxy,就是jdk代理
- ( 1)原理上:JDK动态动态代理的原理是根据 InvocationHandler 中的invoke()方法,由jdk为你的接口手动生成了一个实现了对应接口的类,因此,你的接口可以调用,这是理解mybatis接口没有实现类能被调用的关键。
- ( 2)功能上:可以看出mybatis中的接口就是XML文件的描述,一方面这样做的目的是和spring集成,将接口交给spring管理;另一方面是为了更加方便的管理XML文件(使用接口的package+interface作为namespace,method作为ID)
15.spring+mybatis注解方式是怎样在没有实现类的dao接口的情况下结合的?
spring+mybatis注解方式,也是没有实现类的,但是spring会默认返回MapperFactoryBean对象作为实现类的替换,但是这个只是被spring使用的,mybatis本身还是通过jdk代理来运行的。