天天看點

Mybatis面試題

什麼是MyBatis?

MyBatis是一個可以自定義SQL、存儲過程和進階映射的持久層架構

講下MyBatis的緩存

MyBatis的緩存分為一級緩存和二級緩存,一級緩存放在session裡面,預設就有,二級緩存放在它的命名空間裡,預設是不打開的,使用二級緩存屬性類需要實作Serializable序列化接口(可以用來儲存對象的狀态),可在它的映射檔案中配置

MyBatis是如何進行分頁的,分頁插件的原理是什麼?

1)Mybatis使用RowBounds對象進行分頁,也可以直接編寫sql實作分頁,也可以使用Mybatis的分頁插件。

2)分頁插件的原理:實作Mybatis提供的接口,實作自定義插件,在插件的攔截方法内攔截待執行的sql,然後重寫sql。

舉例:select * from student,攔截sql後重寫為:select t.* from (select * from student)t limit 0,10

簡述Mybatis的插件運作原理,以及如何編寫一個插件?

答:

1)Mybatis僅可以編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis通過動态代理,為需要攔截的接口生成代理對象以實作接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,當然,隻會攔截那些你指定需要攔截的方法。

2)實作Mybatis的Interceptor接口并複寫intercept()方法,然後在給插件編寫注解,指定要攔截哪一個接口的哪些方法即可,記住,别忘了在配置檔案中配置你編寫的插件。

Mybatis動态sql是做什麼的?都有哪些動态sql?能簡述一下動态sql的執行原理不?

1)Mybatis動态sql可以讓我們在Xml映射檔案内,以标簽的形式編寫動态sql,完成邏輯判斷和動态拼接sql的功能。

2)Mybatis提供了9種動态sql标簽:trim|where|set|foreach|if|choose|when|otherwise|bind。

3)其執行原理為,使用OGNL從sql參數對象中計算表達式的值,根據表達式的值動态拼接sql,以此來完成動态sql的功能。

#{}和${}的差別是什麼?

1)#{}是預編譯處理,${}是字元串替換。

2)Mybatis在處理#{}時,會将sql中的#{}替換為?号,調用PreparedStatement的set方法來指派;

3)Mybatis在處理${}時,就是把${}替換成變量的值。

4)使用#{}可以有效的防止SQL注入,提高系統安全性

為什麼說Mybatis是半自動ORM映射工具?它與全自動的差別在哪裡?

Hibernate屬于全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關系模型直接擷取,是以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,是以,稱之為半自動ORM映射工具。

Mybatis是否支援延遲加載?如果支援,它的實作原理是什麼?

1)Mybatis僅支援association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置檔案中,可以配置是否啟用延遲加載lazyLoadingEnabled=true|false。

2)它的原理是,使用CGLIB建立目标對象的代理對象,當調用目标方法時,進入攔截器方法,比如調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先儲存好的查詢關聯B對象的sql,把B查詢上來,然後調用a.setB(b),于是a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。

MyBatis的好處是什麼?

1)MyBatis把sql語句從Java源程式中獨立出來,放在單獨的XML檔案中編寫,給程式的維護帶來了很大便利。

2)MyBatis封裝了底層JDBC API的調用細節,并能自動将結果集轉換成Java Bean對象,大大簡化了Java資料庫程式設計的重複工作。

3)因為MyBatis需要程式員自己去編寫sql語句,程式員可以結合資料庫自身的特點靈活控制sql語句,是以能夠實作比Hibernate等全自動orm架構更高的查詢效率,能夠完成複雜查詢。

簡述Mybatis的Xml映射檔案和Mybatis内部資料結構之間的映射關系?

Mybatis将所有Xml配置資訊都封裝到All-In-One重量級對象Configuration内部。在Xml映射檔案中,<parameterMap>标簽會被解析為ParameterMap對象,其每個子元素會被解析為ParameterMapping對象。<resultMap>标簽會被解析為ResultMap對象,其每個子元素會被解析為ResultMapping對象。每一個<select>、<insert>、<update>、<delete>标簽均會被解析為MappedStatement對象,标簽内的sql會被解析為BoundSql對象。

什麼是MyBatis的接口綁定,有什麼好處?

接口映射就是在MyBatis中任意定義接口,然後把接口裡面的方法和SQL語句綁定,我們直接調用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設定.

接口綁定有幾種實作方式,分别是怎麼實作的?

接口綁定有兩種實作方式,一種是通過注解綁定,就是在接口的方法上面加上@Select@Update等注解裡面包含Sql語句來綁定,另外一種就是通過xml裡面寫SQL來綁定,在這種情況下,要指定xml映射檔案裡面的namespace必須為接口的全路徑名.

什麼情況下用注解綁定,什麼情況下用xml綁定?

當Sql語句比較簡單時候,用注解綁定;當SQL語句比較複雜時候,用xml綁定,一般用xml綁定的比較多

MyBatis實作一對一有幾種方式?具體怎麼操作的?

有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,隻查詢一次,通過在resultMap裡面配置association節點配置一對一的類就可以完成;嵌套查詢是先查一個表,根據這個表裡面的結果的外鍵id,去再另外一個表裡面查詢資料,也是通過association配置,但另外一個表的查詢通過select屬性配置。

Mybatis能執行一對一、一對多的關聯查詢嗎?都有哪些實作方式,以及它們之間的差別?

能,Mybatis不僅可以執行一對一、一對多的關聯查詢,還可以執行多對一,多對多的關聯查詢,多對一查詢,其實就是一對一查詢,隻需要把selectOne()修改為selectList()即可;多對多查詢,其實就是一對多查詢,隻需要把selectOne()修改為selectList()即可。關聯對象查詢,有兩種實作方式,一種是單獨發送一個sql去查詢關聯對象,賦給主對象,然後傳回主對象。另一種是使用嵌套查詢,嵌套查詢的含義為使用join查詢,一部分列是A對象的屬性值,另外一部分列是關聯對象B的屬性值,好處是隻發一個sql查詢,就可以把主對象和其關聯對象查出來。

MyBatis裡面的動态Sql是怎麼設定的?用什麼文法?

MyBatis裡面的動态Sql一般是通過if節點來實作,通過OGNL文法來實作,但是如果要寫的完整,必須配合where,trim節點,where節點是判斷包含節點有内容就插入where,否則不插入,trim節點是用來判斷如果動态語句是以and 或or開始,那麼會自動把這個and或者or取掉。

Mybatis是如何将sql執行結果封裝為目标對象并傳回的?都有哪些映射形式?

第一種是使用标簽,逐一定義列名和對象屬性名之間的映射關系。

第二種是使用sql列的别名功能,将列别名書寫為對象屬性名,比如T_NAME AS NAME,對象屬性名一般是name,小寫,但是列名不區分大小寫,Mybatis會忽略列名大小寫,智能找到與之對應對象屬性名,你甚至可以寫成T_NAME AS NaMe,Mybatis一樣可以正常工作。

有了列名與屬性名的映射關系後,Mybatis通過反射建立對象,同時使用反射給對象的屬性逐一指派并傳回,那些找不到映射關系的屬性,是無法完成指派的。

Xml映射檔案中,除了常見的select|insert|updae|delete标簽之外,還有哪些标簽?

還有很多其他的标簽,resultMap、parameterMap、sql、include、selectKey,加上動态sql的9個标簽,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中為sql片段标簽,通過标簽引入sql片段,selectKey為不支援自增的主鍵生成政策标簽。

當實體類中的屬性名和表中的字段名不一樣,如果将查詢的結果封裝到指定pojo?

1)通過在查詢的sql語句中定義字段名的别名。

2)通過resultMap來映射字段名和實體類屬性名的一一對應的關系。

模糊查詢的語句怎麼寫

第一種:直接傳參法:在java代碼添加sql通配符

string wildcardname = "%smi%";
list<name> names = mapper.selectlike(wildcardname);

<select id="selectlike">
		select * from foo where bar like #{value}
</select>
           

第二種:在sql語句中拼接通配符,會引起sql注入

string wildcardname = "smi";
list<name> names = mapper.selectlike(wildcardname);

<select id="selectlike">
select * from foo where bar like "%"${value}"%"
</select>
           

第三種:CONCAT()函數

MySQL的 CONCAT()函數用于将多個字元串連接配接成一個字元串,是最重要的mysql函數之一。

List<RoleEntity> selectBykeyWord(@Param("keyword") String keyword);

<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">
  SELECT
    *
  FROM
    t_role
  WHERE
    role_name LIKE CONCAT('%',#{keyword},'%')
  OR
    id LIKE CONCAT('%',#{keyword},'%')
  OR
    role_type LIKE CONCAT('%',#{keyword},'%')
</select>
           

第四種:MyBatis的bind

List<RoleEntity> selectBykeyWord(@Param("keyword") String keyword);

<select id="selectBykeyWord" parameterType="string" resultType="com.why.mybatis.entity.RoleEntity">
    <bind name="pattern" value="'%' + keyword + '%'" />
    SELECT
    *
    FROM
    t_role
    WHERE
    role_name LIKE #{pattern}
    OR
    id LIKE #{pattern}
    OR
    role_type like #{pattern}
  </select>
           

通常一個Xml映射檔案,都會寫一個Dao接口與之對應, Dao的工作原理,是否可以重載?

不能重載,因為通過Dao尋找Xml對應的sql的時候全限名+方法名的儲存和尋找政策。接口工作原理為jdk動态代理原理,運作時會為dao生成proxy,代理對象會攔截接口方法,去執行對應的sql傳回資料。

Mybatis映射檔案中,如果A标簽通過include引用了B标簽的内容,請問,B标簽能否定義在A标簽的後面,還是說必須定義在A标簽的前面?

雖然Mybatis解析Xml映射檔案是按照順序解析的,但是,被引用的B标簽依然可以定義在任何地方,Mybatis都可以正确識别。原理是,Mybatis解析A标簽,發現A标簽引用了B标簽,但是B标簽尚未解析到,尚不存在,此時,Mybatis會将A标簽标記為未解析狀态,然後繼續解析餘下的标簽,包含B标簽,待所有标簽解析完畢,Mybatis會重新解析那些被标記為未解析的标簽,此時再解析A标簽時,B标簽已經存在,A标簽也就可以正常解析完成了。

Mybatis的Xml映射檔案中,不同的Xml映射檔案,id是否可以重複?

不同的Xml映射檔案,如果配置了namespace,那麼id可以重複;如果沒有配置namespace,那麼id不能重複;畢竟namespace不是必須的,隻是最佳實踐而已。原因就是namespace+id是作為Map<String, MappedStatement>的key使用的,如果沒有namespace,就剩下id,那麼,id重複會導緻資料互相覆寫。有了namespace,自然id就可以重複,namespace不同,namespace+id自然也就不同。

Mybatis中如何執行批處理?

使用BatchExecutor完成批處理

mybatis都有哪些Executor執行器?它們之間的差別是什麼?

Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

1)SimpleExecutor:每執行一次update或select,就開啟一個Statement對象,用完立刻關閉Statement對象。

2)ReuseExecutor:執行update或select,以sql作為key查找Statement對象,存在就使用,不存在就建立,用完後,不關閉Statement對象,而是放置于Map

3)BatchExecutor:完成批處理。

Mybatis中如何指定使用哪一種Executor執行器?

在Mybatis配置檔案中,可以指定預設的ExecutorType執行器類型,也可以手動給DefaultSqlSessionFactory的建立SqlSession的方法傳遞ExecutorType類型參數。

Mybatis執行批量插入,能傳回資料庫主鍵清單嗎?

能,JDBC都能,Mybatis當然也能。

Mybatis是否可以映射Enum枚舉類?

Mybatis可以映射枚舉類,不單可以映射枚舉類,Mybatis可以映射任何對象到表的一列上。映射方式為自定義一個TypeHandler,實作TypeHandler的setParameter()和getResult()接口方法。TypeHandler有兩個作用,一是完成從javaType至jdbcType的轉換,二是完成jdbcType至javaType的轉換,展現為setParameter()和getResult()兩個方法,分别代表設定sql問号占位符參數和擷取列查詢結果。

如何擷取自動生成的(主)鍵值?

配置檔案設定usegeneratedkeys 為true

在mapper中如何傳遞多個參數?

1)直接在方法中傳遞參數,xml檔案用#{0} #{1}來擷取

2)使用 @param 注解:這樣可以直接在xml檔案中通過#{name}來擷取

resultType resultMap的差別?

1)類的名字和資料庫相同時,可以直接設定resultType參數為Pojo類

2)若不同,需要設定resultMap 将結果名字和Pojo名字進行轉換

使用MyBatis的mapper接口調用時有哪些要求?

1)Mapper接口方法名和mapper.xml中定義的每個sql的id相同

2)Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同

3)Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同

4)Mapper.xml檔案中的namespace即是mapper接口的類路徑。

Mybatis比IBatis比較大的幾個改進是什麼?

1)有接口綁定,包括注解綁定sql和xml綁定Sql

2)動态sql由原來的節點配置變成OGNL表達式

3) 在一對一,一對多的時候引進了association,在一對多的時候引入了collection節點,不過都是在resultMap裡面配置

IBatis和MyBatis在核心處理類分别叫什麼?

IBatis裡面的核心處理類交SqlMapClient,MyBatis裡面的核心處理類叫做SqlSession。

IBatis和MyBatis在細節上的不同有哪些?

1)在sql裡面變量命名有原來的#變量# 變成了#{變量}

2)原來的$變量$變成了${變量}

3)原來在sql節點裡面的class都換名字交type

4)原來的queryForObject queryForList 變成了selectOne selectList5)原來的别名設定在映

射檔案裡面放在了核心配置檔案裡

繼續閱讀