1、#{}和${}的区别是什么?
#{}就是SQL中的?号,调用preparedStatement的set方法来复制,防止sql注入,提高系统安全。
${}替换成变量的值
2、Mybatis和ORM、hibernate(jpa)有什么区别?(Object Relation Mapping)
mybatis和hibernate都同处于持久层的框架。
mybatis是粗粒度封装,hibernate是细粒度封装。
mybatis是一个半ORM(对象关系映射)框架,内部封装了JDBC,开发是只关注sql语句,不需要加载驱动,创建连接等繁杂操作
hibernate对象关系映射能力强,直接面向对象编程,不用关心sql
3、Mybatis怎么封装动态SQL?(常见的动态sql的标签)
where,if,set,foreach,trim,choose,when,otherwise
4、Mybatis怎么实现分页?
利用分页插件pageHelper,基本原理是,使用mybatis提供的插件接口,实现自定义插件,在插件的方法内拦截要执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
5、Mybatis使用了哪些设计模式?
MyBatis中用到的设计模式_mybatis用到哪些设计模式-CSDN博客
Builder模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。例如:
SqlSessionFactoryBuilder
、XMLConfigBuilder
一般来说,如果一个对象的构建比较复杂,超出了构造函数的包含范围,就可以使用工厂模式和Builder模式。相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象创建。在规范中遇到多个构造器参数时,就可以考虑构建者模式。
单例模式
单例模式确保某个类只能有一个实例,而且自行实例化并向整个系统提供这个实例。这个类为单例类,提供全局访问的方法。
工厂模式
比如
SqlSessionFactory
使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单的工厂模式简单工厂模式(
Simple Factory Pattern
)可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其它类的实例,被创建的实例通常都具有共同的父类
代理模式
代理模式是Mybatis的核心使用的模式。
代理模式(Proxy Pattern)定义:它是一个对象结构型模式,给某个对象提供一个代理,并由代理对象控制对原对象的引用。
模板方法模式
定义:一个设计师给出一个算法的轮廓和骨架,另一个设计师给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法叫做基本方法。把这些基本方法汇总起来就是模板方法。例如:
BaseExcutor
、SimpleExecutor
6、Mybatis如何实现主键回填?
可以联动业务场景
在购物交易的时候,付完钱之后一般都会返回一个订单编号,其实这个订单编号在数据库中就是主键,但是在插入时id的值为null,所以订单编号应该为null。
如果插入数据的时候写id,数据量庞大起来就是很科学
还有个方法就是插入后再查寻这条数据,但是非常麻烦。
所以诞生了主键回填
什么是主键回填?
|——把插入数据时,把插入为null的主键id数据填回去。实现添加+查询一步到位。
主键自增
这种方式比较简单,就是在插入节点上添加useGeneratedKeys属性,同时设置接收回传主键的属性。(配置完成后,我们执行一个插入操作,插入时传入一个对象,插入完成后,这个对象的 id 就会被自动赋值,值就是刚刚插入成功的id。)
<insert id="insertBook" userGeneraterKeys="true" keyProperty="id"> insert into t_book(b_name,author) values (#{name},#{author}); </insert>
自定义主键自增
利用MySQL自带的
last_insert_id()
函数查询刚刚插入的id,这种方式是在 insert 节点中添加 selectKey 来实现主键回填,可以再插入前执行,也可以再插入后执行
<insert id="insertBook"> <selectKey order="BEFORE" keyProperty="id" resultType="java.lang.Interger"> SELECT LAST_INSERT_ID(); </selectKey> insert into t_book(b_name,author) values (#{name},#{author}); </insert> //order:sql语句再插入语句中的执行顺序
7、Mybatis一级缓存和二级缓存有什么区别?
一级缓存SqlSession级别的缓存,作用域SqlSession内,底层使用map集合实现,当Session flush或close之后,Session中的Cache将会清空,默认打开一级缓存
二级缓存时SqlSessionFactory级别的缓存,作用域是针对mapper进行缓存,不同的sqlSession可以共享。默认不打开二级缓存,要开启二级缓存,要实现Serializable序列化接口,可以映射文件中的配置。
8、mybatis的实现原理?
读取mybatis的全局配置文件
加载映射文件,该文件配置了操作数据库的sql语句
构造会话工厂SqlSessionFactory
构建会话对象SqlSession,对象包含执行sql语句的所有方法
Executor执行器操作数据库,根据SqlSession传递的参数动态的生成要执行的sql语句,负责查询缓存的维护
MappedStatement对象是映射信息的封装,用于存储要映射的sql语句的id、参数等信息,
输入参数映射。参数类型可以是map、list、基本数据类型,pojo类型
输出结果映射。
源码:
根据配置文件初始出Configuration对象
创建一个DefaultSqlSession对象,它里面包括Configuration和Exucutor
执行DefaultSqlSession.getMapper(),拿到Mapper接口对的MapperProxy
MapperProxy就有DefaultSqlSession
执行增删改查方法:
调用DefaultSqlSession的crud
创建一个StatementHandler对象
调用StatementHandler预编译参数以及设置参数值;使用ParameterHandler的crud方法
调用StatementHandler的crud方法
ResultSetHandler封装结果
9、插件原理?
在MyBatis中插件是通过拦截器来实现的,拦截的对象为Executor、StatementHandler、ParameterHandler、ResultSetHandler。
将四大对象都放到pluginAll做一个处理,有返回一个对象。对原对象进行动态代理,代理的时候加入拦截器执行。注意并不是四大对象的所有方法都会拦截。
10、通常一个Xml映射文件,都会写一个Dao接口与之对应, 请问,这个Dao接口的工作原理是什么?
Dao接口里的方法, 参数不同时,方法能重载吗?
Dao接口,也叫mapper接口。接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
11、如何执行批量插入?
foreach,通过拼接sql语句的方式完成批量操作的。拼接的sql语句过多,导致sql大小超过了mysql服务器中max_allowed_packet变量的值,抛出PacketTooBigException异常,在mysql上调大该值,默认为4M
批量插入,打开sqlSession的时候指定:ExecutorType.BATCH
12、MyBatis实现一对一映射,一对多映射
association
collection
13、Mybatis是否支持延迟加载?
如果支持,它的实现原理是什么?
mybatis仅支持association关联对象和collection关联集合对象的延迟加载。在mybatis配置文件中,可以配置是否启用延迟加载(lazyLoadingEnabled),默认是关闭的,使用的时候在发送sql去进行查询。
原理是使用cglib(code generation library)创建目标对象的代理对象。当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。