昨天剛剛面完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…