Java面試題2.0--mybatis

歡迎關注《Java面試題2.0》合集發佈頁,持續更新中!

 
 
 
#{}和${}的區別是什麼?
 
答:${}是Properties文件中的變量佔位符,它可以用於標籤屬性值和sql內部,屬於靜態文本替換,比如${driver}會被靜態替換爲com.mysql.jdbc.Driver。#{}是sql的參數佔位符,Mybatis會將sql中的#{}替換爲?號,在sql執行前會使用PreparedStatement的參數設置方法,按序給sql的?號佔位符設置參數值,比如ps.setInt(0, parameterValue),#{item.name}的取值方式爲使用反射從參數對象中獲取item對象的name屬性值,相當於param.getItem().getName()。
 
1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #user_id#,如果傳入的值是111,那麼解析成sql時的值爲order by "111", 如果傳入的值是id,則解析成的sql爲order by "id".
2. $將傳入的數據直接顯示生成在sql中。如:order by $user_id$,如果傳入的值是111,那麼解析成sql時的值爲order by user_id, 如果傳入的值是id,則解析成的sql爲order by id.
3. #方式能夠很大程度防止sql注入。 $方式無法防止Sql注入。$方式一般用於傳入數據庫對象,例如傳入表名. 一般能用#的就別用$. MyBatis排序時使用order by 動態參數時需要注意,用$而不是#
 
Xml映射文件中,除了常見的select|insert|updae|delete標籤之外,還有哪些標籤
 
答:還有很多其他的標籤,<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>爲sql片段標籤,通過<include>標籤引入sql片段,<selectKey>爲不支持自增的主鍵生成策略標籤。
 
resultType和resultMap
 
resultType用於返回值只有一個字段的類型,resultMap用於返回值有多個字段的類型。
 
最佳實踐中,通常一個Xml映射文件,都會寫一個Dao接口與之對應,請問,這個Dao接口的工作原理是什麼?Dao接口裏的方法,參數不同時,方法能重載嗎?
 
答:Dao接口,就是人們常說的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串作爲key值,可唯一定位一個MappedStatement,舉例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace爲com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MappedStatement對象。
 
Dao接口裏的方法,是不能重載的,因爲是全限名+方法名的保存和尋找策略。
 
Dao接口的工作原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Dao接口生成代理proxy對象,代理對象proxy會攔截接口方法,轉而執行MappedStatement所代表的sql,然後將sql執行結果返回。
 
Mybatis是如何進行分頁的?分頁插件的原理是什麼?
 
答:Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁,可以在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。
 
分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,然後重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。
 
舉例:select * from student,攔截sql後重寫爲:select t.* from (select * from student)t limit 0,10
 
簡述Mybatis的插件運行原理,以及如何編寫一個插件。
 
答:Mybatis僅可以編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,爲需要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,當然,只會攔截那些你指定需要攔截的方法。
 
實現Mybatis的Interceptor接口並複寫intercept()方法,然後在給插件編寫註解,指定要攔截哪一個接口的哪些方法即可,記住,別忘了在配置文件中配置你編寫的插件。
 
Mybatis執行批量插入,能返回數據庫主鍵列表嗎?
 
答:能,JDBC都能,Mybatis當然也能。
 
Mybatis動態sql是做什麼的?都有哪些動態sql?能簡述一下動態sql的執行原理不?
 
答:Mybatis動態sql可以讓我們在Xml映射文件內,以標籤的形式編寫動態sql,完成邏輯判斷和動態拼接sql的功能,Mybatis提供了9種動態sql標籤trim|where|set|foreach|if|choose|when|otherwise|bind。
 
其執行原理爲,使用OGNL從sql參數對象中計算表達式的值,根據表達式的值動態拼接sql,以此來完成動態sql的功能。
 
Mybatis是如何將sql執行結果封裝爲目標對象並返回的?都有哪些映射形式?
 
答:第一種是使用<resultMap>標籤,逐一定義列名和對象屬性名之間的映射關係。第二種是使用sql列的別名功能,將列別名書寫爲對象屬性名,比如T_NAME AS NAME,對象屬性名一般是name,小寫,但是列名不區分大小寫,Mybatis會忽略列名大小寫,智能找到與之對應對象屬性名,你甚至可以寫成T_NAME AS NaMe,Mybatis一樣可以正常工作。
 
有了列名與屬性名的映射關係後,Mybatis通過反射創建對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性,是無法完成賦值的。
 
Mybatis能執行一對一、一對多的關聯查詢嗎?都有哪些實現方式,以及它們之間的區別。
 
答:能,Mybatis不僅可以執行一對一、一對多的關聯查詢,還可以執行多對一,多對多的關聯查詢,多對一查詢,其實就是一對一查詢,只需要把selectOne()修改爲selectList()即可;多對多查詢,其實就是一對多查詢,只需要把selectOne()修改爲selectList()即可。
 
關聯對象查詢,有兩種實現方式,一種是單獨發送一個sql去查詢關聯對象,賦給主對象,然後返回主對象。另一種是使用嵌套查詢,嵌套查詢的含義爲使用join查詢,一部分列是A對象的屬性值,另外一部分列是關聯對象B的屬性值,好處是隻發一個sql查詢,就可以把主對象和其關聯對象查出來。
 
那麼問題來了,join查詢出來100條記錄,如何確定主對象是5個,而不是100個?其去重複的原理是<resultMap>標籤內的<id>子標籤,指定了唯一確定一條記錄的id列,Mybatis根據<id>列值來完成100條記錄的去重複功能,<id>可以有多個,代表了聯合主鍵的語意。
 
同樣主對象的關聯對象,也是根據這個原理去重複的,儘管一般情況下,只有主對象會有重複記錄,關聯對象一般不會重複。
 
舉例:下面join查詢出來6條記錄,一、二列是Teacher對象列,第三列爲Student對象列,Mybatis去重複處理後,結果爲1個老師6個學生,而不是6個老師6個學生。
 
       t_id    t_name           s_id
 
|          1 | teacher      |      38 |
|          1 | teacher      |      39 |
|          1 | teacher      |      40 |
|          1 | teacher      |      41 |
|          1 | teacher      |      42 |
|          1 | teacher      |      43 |
 
什麼是延遲加載?
 
舉個例子:如果查詢訂單並且關聯查詢用戶信息。如果先查詢訂單信息即可滿足要求,當我們需要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。 所以延遲加載即先從單表查詢、需要時再從關聯表去關聯查詢,大大提高數據庫性能,因爲查詢單表要比關聯查詢多張錶速度要快。
 
也就是說,我把關聯查詢分兩次來做,而不是一次性查出所有的。第一步只查詢單表orders,必然會查出orders中的一個user_id字段,然後我再根據這個user_id查user表,也是單表查詢。
 
Mybatis是否支持延遲加載?如果支持,它的實現原理是什麼?
 
答:Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,可以配置是否啓用延遲加載lazyLoadingEnabled=true|false。
 
它的原理是,使用CGLIB創建目標對象的代理對象,當調用目標方法時,進入攔截器方法,比如調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,然後調用a.setB(b),於是a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。
 
當然了,不光是Mybatis,幾乎所有的包括Hibernate,支持延遲加載的原理都是一樣的。
 
Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重複?
 
答:不同的Xml映射文件,如果配置了namespace,那麼id可以重複;如果沒有配置namespace,那麼id不能重複;畢竟namespace不是必須的,只是最佳實踐而已。
 
原因就是namespace+id是作爲Map<String, MappedStatement>的key使用的,如果沒有namespace,就剩下id,那麼,id重複會導致數據互相覆蓋。有了namespace,自然id就可以重複,namespace不同,namespace+id自然也就不同。
 
association和collection的區別是什麼?
 
1、association表示的是has one的關係,一對一時使用。user has one card,所以在user的resultMap中接收card時應該用association;
2、collection表示的是has many的關係,一對多時使用。user has many mobilePhone,所以在user的resultMap中接收mobilePhone時應該用collection 。
 
Mybatis中如何執行批處理?
 
答: 在有大量數據操作時,同時發幾萬至幾百條數據同時,執行insert,update時,沒有及時commit,釋放資源,會幹掛掉數據庫服務器的,所以我們有必要,分批次處理數據的插入和更新。使用BatchExecutor完成批處理。
 
Mybatis都有哪些Executor執行器?它們之間的區別是什麼?
 
答:Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
 
SimpleExecutor:每執行一次update或select,就開啓一個Statement對象,用完立刻關閉Statement對象。
 
ReuseExecutor:執行update或select,以sql作爲key查找Statement對象,存在就使用,不存在就創建,用完後,不關閉Statement對象,而是放置於Map<String, Statement>內,供下一次使用。簡言之,就是重複使用Statement對象。
 
BatchExecutor:執行update(沒有select,JDBC批處理不支持select),將所有sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每個Statement對象都是addBatch()完畢後,等待逐一執行executeBatch()批處理。與JDBC批處理相同。
 
作用範圍:Executor的這些特點,都嚴格限制在SqlSession生命週期範圍內。
 
Mybatis中如何指定使用哪一種Executor執行器?
 
答:在Mybatis配置文件中,可以指定默認的ExecutorType執行器類型,也可以手動給DefaultSqlSessionFactory的創建SqlSession的方法傳遞ExecutorType類型參數。
 
Mybatis是否可以映射Enum枚舉類?
 
答:Mybatis可以映射枚舉類,不但可以映射枚舉類,Mybatis可以映射任何對象到表的一列上。映射方式爲自定義一個TypeHandler,實現TypeHandler的setParameter()和getResult()接口方法。TypeHandler有兩個作用,一是完成從javaType至jdbcType的轉換,二是完成jdbcType至javaType的轉換,體現爲setParameter()和getResult()兩個方法,分別代表設置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映射文件和Mybatis內部數據結構之間的映射關係?
 
答:Mybatis將所有Xml配置信息都封裝到All-In-One重量級對象Configuration內部。在Xml映射文件中,<parameterMap>標籤會被解析爲ParameterMap對象,其每個子元素會被解析爲ParameterMapping對象。<resultMap>標籤會被解析爲ResultMap對象,其每個子元素會被解析爲ResultMapping對象。每一個<select>、<insert>、<update>、<delete>標籤均會被解析爲MappedStatement對象,標籤內的sql會被解析爲BoundSql對象。
 
 
爲什麼說Mybatis是半自動ORM映射工具?它與全自動的區別在哪裏?
 
答:Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關係模型直接獲取,所以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,所以,稱之爲半自動ORM映射工具。
 
 
JDBC編程有哪些不足之處,MyBatis是如何解決這些問題的?
 
① 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理數據庫鏈接。
 
② Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
 
③ 向sql語句傳參數麻煩,因爲sql語句的where條件不一定,可能多也可能少,佔位符需要和參數一一對應。
解決: Mybatis自動將java對象映射至sql語句。
 
④ 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執行結果映射至java對象。
 
MyBatis編程步驟是什麼樣的?
 
① 創建SqlSessionFactory 
② 通過SqlSessionFactory創建SqlSession 
③ 通過sqlsession執行數據庫操作 
④ 調用session.commit()提交事務 
⑤ 調用session.close()關閉會話
 
MyBatis與Hibernate有哪些不同?
    
Mybatis和hibernate不同,它不完全是一個ORM框架,因爲MyBatis需要程序員自己編寫Sql語句,不過mybatis可以通過XML或註解方式靈活配置要運行的sql語句,並將java對象和sql語句映射生成最終執行的sql,最後將sql執行的結果再映射生成java對象。 
  
    Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關係數據模型要求不高的軟件開發,例如互聯網軟件、企業運營類軟件等,因爲這類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套sql映射文件,工作量大。 
  
    Hibernate對象/關係映射能力強,數據庫無關性好,對於關係模型要求高的軟件(例如需求固定的定製化軟件)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的缺點是學習門檻高,要精通門檻更高,而且怎麼設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力纔行。 
總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合纔是最好。
 
使用MyBatis的mapper接口調用時有哪些要求?
 
①  Mapper接口方法名和mapper.xml中定義的每個sql的id相同 
②  Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同 
③  Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同 
④  Mapper.xml文件中的namespace即是mapper接口的類路徑。
 
SqlMapConfig.xml中配置有哪些內容?
SqlMapConfig.xml中配置的內容和順序如下: 
properties(屬性)
settings(配置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)
 
簡單的說一下MyBatis的一級緩存和二級緩存?
Mybatis的一級緩存的作用域是同一個SqlSession。首先去緩存中查詢結果集,如果沒有則查詢數據庫,如果有則從緩存取出返回結果集就不走數據庫。Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的java對象。
 
Mybatis的二級緩存即查詢緩存,它的作用域是一個mapper的namespace,即在同一個namespace中查詢sql可以從緩存中獲取數據。二級緩存是可以跨SqlSession的。
 
MyBatis實現一對一有幾種方式?具體怎麼操作的
有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次, 通過在resultMap裏面配置association節點配置一對一的類就可以完成;
嵌套查詢是先查一個表,根據這個表裏面 的結果的外鍵id,去再另外一個表裏面查詢數據,也是通過association配置,但另外一個表 的查詢通過select屬性配置
 
Mybatis比IBatis比較大的幾個改進是什麼
a.有接口綁定,包括註解綁定sql和xml綁定Sql ,
b.動態sql由原來的節點配置變成OGNL表達式,
c. 在一對一,一對多的時候引進了association,在一對多的時候引入了collection 節點,不過都是在resultMap裏面配置
 
什麼是MyBatis的接口綁定,有什麼好處
接口映射就是在IBatis中任意定義接口,然後把接口裏面的方法和SQL語句綁定, 我們直接調用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設置.
 
接口綁定有幾種實現方式,分別是怎麼實現的?
接口綁定有兩種實現方式,一種是通過註解綁定,就是在接口的方法上面加上 @Select@Update等註解裏面包含Sql語句來綁定,
另外一種就是通過xml裏面寫SQL來綁定, 在這種情況下,要指定xml映射文件裏面的namespace必須爲接口的全路徑名.
就插入where,否則不插 入,trim節點是用來判斷如果動態語句是以and 或or開始,那麼會自動把這個and或者or取 掉
 
什麼是MyBatis?
參考答案:
  MyBatis是支持普通SQL查詢,存儲過程和高級映射的優秀持久層框架.MyBatis封裝了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索;MyBatis使用簡單的XML或註解做配置和定義映射關係,將Java的POJOs(Plain Old Java Objects)映射城數據庫中的記錄.
 
Mybait的優點
(1)簡單易學,容易上手(相比於Hibernate) —- 基於SQL編程;
(2)JDBC相比,減少了50%以上的代碼量,消除了JDBC大量冗餘的代碼,不需要手動開關連接;
(3)很好的與各種數據庫兼容(因爲MyBatis使用JDBC來連接數據庫,所以只要JDBC支持的數據庫MyBatis都支持,而JDBC提供了可擴展性,所以只要這個數據庫有針對Java的jar包就可以就可以與MyBatis兼容),開發人員不需要考慮數據庫的差異性。
(4)提供了很多第三方插件(分頁插件 / 逆向工程);
(5)能夠與Spring很好的集成;
(6)MyBatis相當靈活,不會對應用程序或者數據庫的現有設計強加任何影響,SQL寫在XML裏,從程序代碼中徹底分離,解除sql與程序代碼的耦合,便於統一管理和優化,並可重用。
(7)提供XML標籤,支持編寫動態SQL語句。
(8) 提供映射標籤,支持對象與數據庫的ORM字段關係映射。
(9)提供對象關係映射標籤,支持對象關係組建維護。
 
MyBatis框架的缺點:
(1)SQL語句的編寫工作量較大,尤其是字段多、關聯表多時,更是如此,對開發人員編寫SQL語句的功底有一定要求。
(2)SQL語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。
 
MyBatis框架適用場合
(1)MyBatis專注於SQL本身,是一個足夠靈活的DAO層解決方案。
(2)對性能的要求很高,或者需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。
 
一級緩存和二級緩存的源碼分析
一級緩存:
 
在執行查詢操作時,SqlSession最終會調用Executor接口的方法。如果cacheEnabled這個屬性爲true的話,那麼executor會被包一層裝飾器,這個裝飾器是CachingExecutor,其中cacheEnabled這個屬性是mybatis總配置文件中settings節點中cacheEnabled子節點的值,默認就是true,然後最終執行了SimpleExecutor的父類BaseExecutor的query方法。BaseExecutor的屬性localCache是個PerpetualCache類型的實例,實現了MyBatis的Cache緩存接口的實現類之一,這個localCache就是一級緩存!
 
二級緩存:
和一級緩存的原理一樣,只是開關配置不同
 
一級緩存和二級緩存的執行順序是什麼?
 
如果你的MyBatis使用了二級緩存,並且你的Mapper和select語句也配置使用了二級緩存,那麼在執行select查詢的時候,MyBatis會先從二級緩存中取輸入,其次纔是一級緩存,即MyBatis查詢數據的順序是:
二級緩存 ———> 一級緩存——> 數據庫
 
 
緩存會造成哪些問題?
 
雖然一級和二級緩存的使用可以減少數據庫查詢操作,但是都存在造成數據不一致的情況存在:對於一級緩存由於不同sqlSession實例之間相互隔離,則可能出現其中一個更新了數據庫數據,但是另外一個由於使用了自身內部的緩存,故讀取到失效的舊數據;對於二級緩存,由所有sqlSession實例共享,基於namespace隔離,故如果不同namespace定義了同時操作一個表的SQL語句,則會造成不同namespace之間的緩存不一致問題。所以如果對於mybatis的內部運作機制不理解,可能會由於這些造成數據不一致的情況存在,則可能會導致莫名其妙的問題。
針對以上這些問題,建議統一使用額外的緩存實現,即在應用代碼中自定義緩存實現,關閉mybatis的一級和二級緩存,只使用mybatis基於SQL來進行數據庫操作。
 
常用的分頁插件有哪些?
 
1.總體上是利用mybatis的插件攔截器,在sql執行之前攔截,爲查詢語句加上limit X X
2.用一個Page對象,貫穿整個執行流程,這個Page對象需要用java編寫前端分頁組件
3.用一套比較完整的三層entity,dao,service支持這個分頁架構
4.這個分頁用到的一些輔助類
 
逆向工程怎麼用?
 
mybatis的一個主要的特點就是需要程序員自己編寫sql,那麼如果表太多的話,難免會很麻煩,所以mybatis官方提供了一個逆向工程,可以針對單表自動生成mybatis執行所需要的代碼(包括mapper.xml、mapper.java、po..)。一般在開發中,常用的逆向工程方式是通過數據庫的表生成代碼。
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章