昨天刚刚面完spring,根据hr的反馈说面试官对个人总体表现还算满意,而后又通知我今天有空去再聊聊有关的技术。去的路上,我一直在想,今天会问些什么问题,JVM?多线程?仍是分布式......真是越想内心越没底。想着想着就到了,尽管仍是那个熟悉的面试官,但那张年轻有为的面孔丝毫没有让我放下紧张的情绪。他先开口了:昨天的面试感受你挺好的,你说你项目中还用的是mybatis框架做为数据库访问,那咱们今天就来聊聊吧。java
面试官:你先说下你对mybatis的总体理解。mysql
我:MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。它避免了几乎全部JDBC代码和手动设置参数以及获取结果集。MyBatis能够对配置和原生Map使用简单的XML或注解,将接口和Java的POJO映射成数据库中的记录。程序员
面试官:那大家公司为何选择Mybatis,为何不用Hibernate呢?他两有什么区别吗?面试
我:mybatis的着力点在于POJO和SQL之间的映射关系,而后经过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。Hibernate的ORM实现了POJO和数据库表之间的映射,以及SQl的自动生成和执行,也就是说Hibernate会根据制定的存储逻辑,自动生成对应的SQl并调用JDBC接口加以执行。下面我经过四个方面对比二者的区别:redis
我:另外,有种说法,mybatis是半自动ORM映射工具,Hibernate是全自动的。这主要就是由于使用Hibernate查询关联对象或集合对象时,能够根据对象关系模型调用api接口直接获取。而Mybatis在查询关联对象或集合对象时,须要手动编写sql来完成,因此叫作半自动。算法
我:至于咱们公司为何选择半自动的mybatis,主要是由于咱们的业务常常须要编写复杂的sql,好比动态的sql。还有这种更便于咱们使用索引来优化sql语句。spring
面试官:你先说下JDBC的执行流程吧sql
我:(1)加载JDBC驱动(2)创建并获取数据库链接(3)建立JDBC Statements对象(4)设置SQL语句的传入参数(5)执行SQL语句并得到查询结果(6)对查询结果进行转换处理并将处理结果返回(7)释放相关资源(关闭Connection,关闭Statement,关闭ResultSet)数据库
面试官:那你能说下mybatis执行SQL的流程吗?api
我:好的。
面试官:很好。你刚说到初始化,你对mybatis初始化了解吗?
我:能够这么说,Myabtis初始化的过程就是建立Configuration对象的过程。过程也很简单:(1)加载配置文件mybatis-config.xml到Mybatis内部。(2)使用Configuration对象做为一个全部配置信息的容器,这个对象的组织结构和XML配置文件的组织结构几乎彻底同样,这样配置文件的信息就能够存到这个对象中,访问起来很方便。
面试官:那我问的再深刻一点,你看过mybatis的源码吗?
我:没看过。。关键的类仍是知道一点的。
面试官:哦,那你说下你了解的mybatis的有哪些核心的类?
我:(心想:既然面试前准备了,仍是要说的,否则怎么显得本身nb一些)
另外,附赠一张mybatis的层次结构图: mybatis层次结构.png
面试官:那你能说下mybatis源码中的主要部件吗?
我:(1)SqlSession:做为mybatis工做的主要顶层API,表示和数据库交互的会话,完成必要的数据库增删改查功能。(2)Executor:mybatis执行器,是Mybatis调度的核心,负责SQL语句的生成和查询缓存的维护。(3)StatementHandler:封装了JDBCStatement操做,负责对JDBC Statement的操做。(4)ParameterHandler:负责对用户传递的参数转换成JDBC Statement所须要的参数。(5)ResultSetHandler:负责将JDBC返回的ResultSet结果集转换成List类型的集合。(6)TypeHandler:负责Java数据类型和jdbc数据类型之间的映射和转换。(7)MappedStatement:维护了一条select/update/delete/insert节点的封装。(8)Sqlsource:负责根据用户传递的parameterObject,动态生成SQL语句,将信息封装在BoundSql对象中,并返回。(9)BoundSql:表示动态生成的SQL语句以及相应的参数信息。(10)Configuration:Mybatis全部的配置信息都维护在这个对象中。
面试官:原理聊完了,接下来咱们聊下实战吧。。你在项目中是怎么整合spring和mybatis的?
我:我先说下xml的配置方式吧。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>x.x.x</version>
</dependency>
复制代码
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 当mybatis的xml文件和mapper接口不在相同包下时,须要用mapperLocations属性指定xml文件的路径。
*是个通配符,表明全部的文件,**表明全部目录下 -->
<property name="mapperLocations" value="classpath:mapper/**/*.xml"/>
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
</bean>
复制代码
2.1:datasource:是数据源配置,经常使用的有DBCP,C3P0,Druid等。 2.2:mapperLocations:是指接口xml的文件配置,若是不配置的话映射接口类文件(mapper接口)和映射xml文件(mapper.xml)须要放在相同的包下。 3. 配置数据映射器类:利用mybatis-spring提供的自动扫描机制:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<!-- 自动扫描 -->
<mybatis:scan base-package="org.mybatis.spring.sample.mapper" />
</beans>
复制代码
我:(接着说)如今好像大多使用的是注解配置mybatis和数据源的方式,也就是使用java代码和spring提供的注解。(其实步骤大体差很少,因为涉及安全问题代码不透露,想学习的能够网上找。)
面试官:你能写一个mapper映射文件中select的sql语句吗?
我:随手写了一个,接着解释到:这个语句被称做selectPerson,接收一个int类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值即是结果行中的对应值。
<select id="selectPerson" parameterType = "int" resultType="hashmap"
select * from person where id = #{id}
</select>
复制代码
<select id="getByOrderId" parameterType="java.lang.Long" resultType="com.demo.entity.OrderInfo">
select order_id OrderId, order_sn orderSn, total_fee totalFee, create_time createTime
from order_info where order_id=#{orderId}
</select>
复制代码
<resultMap id = "BaseResultMap" type="com.demo.entity.OrderInfo">
<id property="OrderId" column="order_id"/>
<result property="orderSn" column="order_sn"/>
<result property="totalFee" column="total_fee"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="getByOrderId" parameterType="java.lang.Long" resultMap="BaseResultMap">
select order_id, order_sn, total_fee, create_time
from order_info where order_id=#{orderId}
</select>
复制代码
<insert id='insert' parameterType="com.demo.entity.OrderInfo"
<selectKey keyProperty="orderId" order="AFTER" resultType="java.lang.Long">
select LAST_INSERT_ID()
</selectKey>
insert into order_info(order_sn,total_fee,create_time)
values(#{orderSn},#{totalFee},#{createTime)
</insert>
复制代码
<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE 1=1
<where>
<choose>
<when test="Name!=null and student!='' ">
AND name LIKE CONCAT(CONCAT('%', #{student}),'%')
</when>
<when test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</when>
<otherwise>
AND AGE = 15
</otherwise>
</choose>
</where>
</select>
复制代码
3.foreach标签:用于循环。例如:
<select id="listByOrderIds" resultMap="BaseResultMap">
select * from order_info where order_id in
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
复制代码
4.另外还有set标签,where标签,trim标签等。
面试官:#{}和${}的区别是什么?
我:#{}是解析传进来的参数,而另外一个是拼接参数到SQl中。#{}是预编译处理,而另外一个是字符串替换。并且#{}能够防止SQL注入。例如:select * from emp where name=#{empName},参数传入empName->Smith,解析执行后的SQL是:select * from emp where name=?。可是对于select * from emp where name=${empName},参数传入empName->Smith,解析执行后的SQL是:select * from emp where name='Smith'。
面试官:在mapper中如何传递多个参数?
我:有两种方法:
//mapper接口
public OrderInfo getByOrderIdAndStatus(Long orderId, String status);
//mapper.xml文件
<select id="getByOrderIdAndStatus" resultMap="BaseResultMap">
select * from order_info where order_id=#{0} and status=#{1}
</select>
复制代码
//mapper接口
public OrderInfo getByOrderIdAndStatus(@param("orderId")Long orderId, @param("status")String status);
//mapper.xml文件
<select id="getByOrderIdAndStatus" resultMap="BaseResultMap">
select * from order_info where order_id=#{orderId} and status=#{status}
</select>
复制代码
2.使用Map集合做为参数来装载
Map<String, Object> map = new HashMap();
map.put("orderId", 1L);
map.put("status", "NORMAL");
OrderInfo orderinfo = getByOrderIdAndStatus(map);
//mapper接口
public OrderInfo getByOrderIdAndStatus(Map<String, Object> map);
//mapper.xml文件
<select id="getByOrderIdAndStatus" parameterType="map" resultMap="BaseResultMap">
select * from order_info where order_id=#{orderId} and status=#{status}
</select>
复制代码
今天面试了吗系列
redis:juejin.im/post/5dccf2…
spring:juejin.im/post/5e6d99…
数据库系列
mysql索引:juejin.im/post/5d6770…
数据库锁:juejin.im/post/5dbbc1…
分库分表:juejin.im/post/5dc77a…
数据库事务:juejin.im/post/5dcb9c…
java零零星星系列
juejin.im/post/5d5e26…
juejin.im/post/5d427f…