面试总结之mybatis

前言:做好及时的总结与回顾,才能有效避免知识的遗忘!!!
 

面试问题一.请介绍mybatis及其优缺点

(1)介绍mybatis
mybatis的前身是apche公司的ibatis,于2010年更名为MyBatis,目前项目源码托管于github;(历史渊源);

它是一款持久层框架,程序员通过编写sql后交给mybatis框架进行处理,省去大量的JDBC冗余代码。 除此之外,mybatis支持缓存,延迟加载,日志和动态sql等功能,是目前javaweb项目首选的数据访问层框架。(功能介绍)

(2)mybatis的优缺点
优点:

第一,简化代码:省去加载驱动,获取连接,对象与记录的手动映射,关闭连接等冗余操作,使得程序员可以有大量精力关注业务实现;

第二,内置缓存机制,从而减少与数据库的交互,提升接口的响应速度;

第三,灵活度高,程序员可以根据不同的业务需求编写相应的sql,得出想要的结果;

第四,良好的数据库兼容性,支持市场上的所有数据库产品;

第五,支持与spring进行整合;(web开发离不开spring,所有支持与spring的项目只要性能优异,都会得到很好的使用)

缺点:

第一,需要一定的sql功底;

第二,移植性能差,不同数据库在相同业务的情况下sql的实现可能不同,开发过程中选定数据库时,不能进行更改,如果需要移植别的数据库,则需要修改大量sql语句;

面试问题二,谈谈你对ORM(Object Relational Mapping)的理解
     
(1)ORM全称Object Relational Mapping,即对象关系映射,它是一种程序设计技术,主要思想是通过开发人员指定java对象和关系型数据库表之间的映射关系,从而使得在程序开发时可以使用面向对象的思想操作关系型数据库;

 (2)在开发初期,如果想要实现数据库的crud操作,我们需要将对象属性进行拆解,放入sql语句中,这个过程也被称为装箱,并将数据库返回值ResultSet对象拆解放入java对象,这个过程也被称为装箱,这些操作需要程序员自己来做,比较繁琐;为了解决该问题,引入ORM框架,目前市面上有两款ORM框架,分别是Hibernate和Mybatis,前者全自动,后者半自动;

没有ORM框架前的java程序操作数据库的代码如下:

//1.加载驱动,驱动可能不安全,需要抛出异常,属于编译期异常;
Class.forName("com.mysql.jdbc.Driver");
//2.用户信息和url;
String url="jdbc:mysql://localhost:3306/su?useUnicode=true&charset=utf8&useSSL=true";
String username="root";
String password="123456";
//3.连接数据库对象
Connection connection= DriverManager.getConnection(url,username,password);
//4.创建执行sql的对象
Statement statement= connection.createStatement();//这个对象也不安全,需要抛出异常
  //5.定义一个sql,并去SQL执行对象去执行
String sql="insert into t_emp values (6,'郭六',1,0)";
int num=statement.executeUpdate(sql);
if(num>0)
{
    System.out.println("插入成功");
}
//6.关闭连接
statement.close();
connection.close();

面试问题三,为什么说mybatis是半自动框架?
标准的ORM框架只需要将对象传递给ORM框架后,由ORM框架生成sql语句,进行参数设置,填充结果后返回;
但是MyBatis框架需要程序员来编写sql(参数设置和填充结果均自动),所以说mybatis是半自动化的orm框架;
 

面试题四,mybatis和hibernate的区别
第一,mybatis比hibernate灵活度高,可以根据业务来编写相应的sql,后续随着数据量的增加,优化起来也比较方便;

第二,mybatis比hibernate简单,学习成本更低,框架使用方便;

第三,Hibernate是标准的ORM框架,在配置了映射关系后,会自动生成sql,参数设置,并进行结果填充。Mybatis是半自动化的ORM框架,在映射关系配置后,需要程序员手动编写sql;

第四,Hibernate移植性强。Hibernate只要要配置方言(dialect),通过方言判断需要转换的sql命令类型,从而适应不同的数据库类型,而mybatis需要自己手动修改sql;

第五,Hibernate的缓存机制更强。Mybatis的缓存是基于<select>标签的,标签内的所有信息一致,才可以使用缓存,Hibernate的缓存基于对象中的OID,只要OID一致,即可使用缓存;

第六,Hibernate日志系统更强。mybatis主要打印sql的执行过程信息,而Hibernate除此之外还可以提示脏读异常信息等;
    
 面试题五,mybatis必须使用mapper接口吗?

mybatis框架并不要求必须有接口。Mybatis提供了三种引入方式:(放在全局配置文件的mappers属性中)

<mappers>
    <mapper resource="com/su/crm/settings/mapper/UserMapper.xml"></mapper>
    <mapper class="com.su.crm.settings.mapper.DicValueMapper"></mapper>
    <package name="com.su.crm.settings.mapper"/>
</mappers>

第一,针对resourse属性,直接引入对应的.xml文件,此时不需要Mapper接口,通过加载该配置文件,实现sql的执行;

第二,针对class属性,必须使用接口,写出接口的全限定名,此时通过在接口方法上使用注解的方式编写sql,不需要.xml配置文件;

第三,针对package属性,必须使用接口,并且保证mapper.xml的命名和接口命名一致;配置文件的namespace属性和接口的全限定名保持一致;配置文件中标签id与接口中的方法名保持一致;参数类型和返回值类型根据接口类中的方法进行相关设定;(开发常用,搭配包扫描注解使用)

<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.su.crm.settings.mapper,com.su.crm.workbench.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

在平时开发时,提供一个接口的目的在于其它层可以通过接口快速注入接口对象,方便调用接口的方法;

面试题六,Mybatis如何实现接口和Mapper.xml进行绑定的?

第一,在全局配置文件中,在mappers标签中提供package属性,指明要绑定的包名;

第二,在对应的包中创建接口和对应的mapper.xml文件;

第三,在mapper.xml的namespace标签中填写接口的全限定名;

第四,编写sql语句时,必须保证id值和方法名完全一致;

此时,可以从应用角度实现接口与Mapper.xml文件的绑定;

底层实现:调用sqlsession的getMapper方法创建了一个接口的代理对象;通过mapper.xml中的namespace和接口的全限定名直接比较,从而实现两者的绑定;使用代理对象的方法实现对sql的调用;        

面试题七,Mybatis接口是否支持方法的重载?

在java中接口是支持方法重载的,但是在mybatis中,接口不允许方法的重载。因为在mapper.xml中的<select><update><insert><delete>这些标签最终的存储都是以namespace+id作为key进行存储,而每个mapper接口对应一个xml文件,所以所有方法的namespace是相同的,方法重载又导致id相同,此时会出现同名key,造成不合法的参数异常状况产生;

面试题八mapper.xml除了支持<select><update><insert><delete>标签外,还支持哪些标签?

<resultMap>结果集映射规则的制定;对应装箱过程,将sql执行的返回结果ResultSet按照结果集映射到相应的java对象属性中;二级标签<result>用于基本属性的装配,<association>用于单个引用对象的装配,<collection>用于集合对象的装配;

<cache>二级缓存的开启;<cache-ref>二级缓存引用,其他表更新时,是否刷新当前表对应的二级缓存;

<sql>sql片段,常用sql代码的封装;

<parameterMap>定义参数映射的规则,对应拆箱过程,与注解@Param功能一样;方法参数较多时,一般使用@Param;

除去这些一级标签外,常用的增删改查标签对应的二级标签有很多,比如说<include>使用sql片段,<where>条件判断对于and的省略,<set>更新参数设置对于逗号的省略;动态sql标签:<if><choose>选择标签<foreach>遍历标签<bind>模糊查询标签;

面试题九,namespace的作用

namespace的使用要求:第一,必须写,否则构建异常,第二,不能空串,不然仍然会发生构建异常,第三,如果需要和接口绑定,必须保证其命名和接口的全限定名一致;(只加载mapper.xml文件不进行接口绑定时,可以随意写,但是必须存在。例如使用resource标签进行一次mybatis的调用,此时不需要接口绑定,命名就可以随便写);

由上述信息可知,namespace的作用是给当前mapper.xml文件中的sql操作做一个分组,以sql的id和namespace结合作为key作为sql的key;

面试题十.mapper.xml中的id是否允许重复?

id属性存在的意义在于与namespace结合作为sql的key,每个sql的key是不可以重复的,所以id是否可以重复和namespace有关;

namespace的默认规则为必须配置且多个mapper.xml允许出现同名的namespace,此时如果namespace相同,里面的id标签是不可以重复的,如果namespace不同,则里面的id标签是可以重复的;

面试题十一.mapper.xml中如何获取对应接口的方法参数?

获取方法参数的值可以在sql语句中使用#{}进行获取;mybatis解析sql时会将#{}当做占位符处理,参数的注入方式需要根据方法参数的具体情况来决定;

第一,如果参数只有一个且参数为简单类型+String+Date时,配置参数类型后,可以使用#{任意内容}就可以实现参数的获取,任意内容不可以为空;如下所示:

select 
<include refid="Base_Column_List" />
from tbl_user
where id = #{abcsdada}

第二,如果参数有两个简单类型时(没有@Param注解),参数获取要么使用parameterMap进行配置,要么就不写,通过方法内参数位置来确定值的获取,#{param1}表示获取接口方法第一个值,#{param2}表示获取接口方法第二个值或#{arg0}表示第一个值,#{arg2}表示第二个值或混合两个使用,不过位置要对应(一个从1开始,一个从0开始);

第三,如果参数有两个(有@Param注解),可以将注解内的参数值写入sql语句中;此时仍然支持#{paramN}的方式进行参数的获取;

第四,如果传入对象是引用类型数据时,只能使用#{对象的属性}从而实现sql值的获取;

面试题十二,#{}和${}的区别

${}会将值解析为字符串,与sql语句进行拼接,存在的意义主要是动态获取表名和列名,实现sql的复用,如果将${}用于参数的注入,还需要注意参数的类型以及sql注入情形;

#{}会解析为占位符 ?,防止sql注入;

面试题十三,Mybatis中结果映射的几种方式

mybatis中结果映射有三种方式:

第一种是自动映射,在构建java对象时,和数据库中字段一致;

第二种是别名方式,在sql语句中,将列起别名,使得数据库中的字段和java对象中的属性进行对应   

第三种是resultMap,将java对象属性和数据库的列字段进行对应,在开发中,一般使用该方式;

面试题十四,实体类中的属性名和数据库中的字段名是否必须相同?

根据结果映射来确定两者是否一致,如果采用自动映射的方式且列没有别名时,出现字段名和属性名不同则无法解析,此时必须相同;

如果采用resultMap或自动映射且列有别名时,只需要保证映射后的值和实体类中的属性名相同即可,原始字段名和属性名不需要相同;

面试题十五.实体类是否必须有getter和setter方法?

不是,mybatis进行参数获取和结果映射时优先使用反射获取对象的getter和setter方法,如果实体类不存在getter和setter方法,会利用反射暴力访问对象中的属性;

面试题十六.如何实现关联对象查询?(多表查询)

在mybatis中,支持两种方式实现关联对象查询:

第一种为N+1查询方式(嵌套子查询),1指的是通过一条sql查询出主表的N条记录,N指的是通过查询出的记录字段再次执行子表的查询;        

业务,查询学生的所有信息(涉及教师表)

第一步,编写子查询(根据学生id查对应的老师信息)

 第二步,编写总查询(将第一个sql整合进来,核心在于select和column,将两个sql进行整合

第二种为多表联合查询方式,将两个表连接,然后通过一条sql进行查询;在查询效率上,多表联合查询优于N+1查询;N+1查询支持延迟加载,而多表联合查询不支持延迟加载;

业务:查询学生所有信息(涉及教师表)

在编写mapper.xml中,如果关联的是一个对象,使用<resultMap>中的<association>实现,如果关联的是一个集合,使用<resultMap>中的<collection>实现;

面试题十七,Mybatis是如何实现延迟加载的?

延迟加载只有在子查询(N+1)方式下生效,有两种方式来实现延迟加载,

第一,在全局配置文件中进行相关配置;

第二,在<association>或<collection>中使用fetchType属性进行控制,lazy表示延迟加载,eager表示立即加载;当全局开关和fetchType属性同时存在时,以fetchType为准;

面试题十八,谈谈mybatis的缓存机制

Mybatis提供了两种缓存,分别称为一级缓存和二级缓存,通过缓存可以减少程序对数据库的访问,提高程序的执行性能;

一级缓存又被称为sqlsession缓存,是默认开启的,每个sqlsession对象缓存自己的内容,把sql当做key,查询的结果当做value进行缓存;当sqlsession对象被垃圾回收时,释放缓存内容;

二级缓存又被称为sqlsessionFactory缓存,有效的范围为一个sqlsessionFactory对象,默认是禁用状态,需要在主配置文件中添加<cache>标签启用二级缓存;当sqlsession提交或者关闭时,会把一级缓存的内容放入二级缓存中;在项目中默认二级缓存是开启后是不关闭的,所以二级缓存一直存在且存放一些经常被查询,很少被修改的内容;

每次进行查询操作时先判断二级缓存中有没有该查询的结果,如果没有,查询一级缓存,如果也不存在,访问数据库,并将查询结果放入一级缓存中;

面试题十九,mybatis的执行器有几种?

mybatis的执行器都实现了Executor接口,目的是控制sql的执行流程,一共三个常用的接口实现类:SimpleExecutor,ReuseExecuter,BatchExecutor;

其中默认使用的是SimpleExecutor类型,特点是每个sql都需要预编译(创建Statement对象),参数设置,sql执行;

ReuseExecuter:只预编译一次,复用Statement对象,然后设置参数,执行(适用于sql相同,参数不同的情况);

BatchExecutor:预编译,批量执行时设置参数,最后统一交给数据库执行(适用于一次执行多条sql);

可以在factory.openSession()中设置参数类型(内部是一个枚举类,枚举类中的每个参数代表一种执行器类型)

面试题二十,Mybatis四大核心接口及其执行流程

Executor:执行器;负责控制sql的执行过程;默认SimpleExecutor

ParameterHandler:参数处理器,负责sql语句中的参数设置;

StatementHandler:负责与jdbc代码的交互,包含prepare预处理,query查询,update增删改操作等方法;

ResultSetHandler:结果处理器,将查询出来的结果封装到java对象中去;

执行流程

第一步,sqlsession对象创建完成之后,确定相应的执行器;

第二步,将sql语句交给statementHandler处理,并调用ParameterHandler对sql的参数进行设置,从而产生一条可用的sql,并执行sql;

最后,将数据库的sql执行结果用ResultSetHandler处理,把字段值根据映射规则封装进java对象的属性中;

面试题二十一,mybatis中如何定义一个插件?

第一步,自定义类并实现Interceptor接口,重写接口中的intercept方法,在该方法中实现插件的逻辑,并使用proceed()方法实现放行操作;

第二步,在该类上标注Intercepts注解,指明拦截的接口类型,拦截的方法以及拦截方法的参数类型;

第三步,将该类通过配置的方式写入在全局配置文件中的plugins中;

面试题二十二,mybatis如何实现动态sql的?

动态sql的本质就是根据不同的条件对sql的拼接,从而实现相应的功能;

在mybatis中通过这些动态sql标签实现动态sql的,包含:

<where>(根据情形去掉and),

<set>(根据情形去掉最后一个逗号),

<foreach>(循环获取数组或者集合内部的值),

<bind>(模糊查询)

面试题二十三,谈谈mybatis支持的日志类型

mybatis的日志默认是没有开启的,可以在mybatis中的全局配置文件中<settings>标签中的logImpl中进行配置;默认有6种日志的实现,SLF4J,LOG4J,LOG4J2,JDK_LOGGING,COMMONS_LOGG以及不需要任何配置就能实现日志功能的STDOUT_LOGGING;

比较常用的是LOG4J,需要配合log4j.properties中参数进行使用

                                                                     主配置类

                                                 自定义的log4j配置文件

面试题二十四,mybatis使用了哪些设计模式?

第一,代理模式,mybatis在运行过程中使用jdk的动态代理模式创建了一个mapper接口的代理类对象;

第二,建造者模式,调用SqlSessionFactoryBuilder的build方法创建SqlSessionFactory对象;

第三,工厂模式,调用sqlSessionFactory的openSession方法创建sqlSession对象;

第四,策略模式,openSession方法参数可以有多种,控制后续的sql执行流程;

第五,模板方法模式,类中方法空实现,交给子类来拓展;

面试题二十五,mybatis的运行原理?

第一步,使用Resouces类将全局配置文件以及相关的Mapper.xml文件转换为输入流InputStream对象;

第二步,将输入流交给XMLConfigBuilder对象做xml解析,解析过程使用的是java的DOM操作,并将解析的结果存储在Configuration对象中(此类存储了xml的所有信息);并将Configuration对象作为参数传入DefaultSqlSessionFactory的构造方法中,从而创建一个DefaultSqlSession对象;

第三步,DefaultSqlSessionFactory对象调用其openSession方法创建了一个sqlSession对象,将配置类信息以及默认执行器接口等信息传递sqlSession对象;

第四步,调用sqlSession对象的getMapper方法,在底层使用jdk动态生成了一个指定Mapper接口的代理对象;(通过MapperProxy类实现InvocationHandler接口重写invoke方法实现代理对象的创建);

第五步,使用代理对象调用接口的方法,此时会根据接口方法的类型以及返回值结果选择调用不同的方法,并将结果映射成java对象(以查询为例,selectOne表示返回值是一个对象,selectList表示返回值是一个List集合,selectMap表示返回值是一个Map集合);

第六步,关闭sqlSession连接;(可以通过在openSession方法处添加参数实现业务执行结束自动关闭连接);

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值