1. 程式人生 > 其它 >mybatis 取查詢值_Mybatis常見問題整理

mybatis 取查詢值_Mybatis常見問題整理

技術標籤:mybatis 取查詢值

c74f561fc5acca6ceef817bc880fd776.png

一.mybatis 中 #{}和 ${}的區別是什麼?

1."#{}"是將傳入的值按照字串的形式進行處理

2."${}"是做簡單的字串替換,即將傳入的值直接拼接到SQL語句中

例如:select user_id,user_name from t_user where user_id = #{user_id}

#{}的執行過程:

(1)Preparing: select id, user_name from t_user where id = ?

(2)Parameters: 1(Long)

解釋:

(1)MyBaits會首先對SQL進行預編譯,將#{user_ids}替換成?佔位符

(2)執行時替換成實際傳入的user_id值,並在兩邊加上單引號,以字串方式處理

注:因為"#{}"會在傳入的值兩端加上單引號,所以可以很大程度上防止SQL注入

${}的執行過程:

(1)Preparing: select id, user_name from t_user where id = 1

(2)Parameters:

解釋:引數是直接替換的,且沒有單引號處理,這樣就有SQL注入的風險。


二.mybatis 有幾種分頁方式?

邏輯分頁:指使用MyBatis自帶的RowBounds進行分頁,它會一次性查出多條資料,然後再檢索分頁中的資料,它是針對ResultSet結果集執行的記憶體分頁

物理分頁:可以在sql內直接書寫帶有物理分頁的引數來完成物理分頁功能,也可以使用分頁外掛來完成物理分頁。


三.RowBounds 是一次性查詢全部結果嗎?為什麼?

1.RowBounds 表面是在“所有”資料中檢索資料,其實並非是一次性查詢出所有資料

2.因為 MyBatis 是對 jdbc 的封裝,在 jdbc 驅動中有一個 Fetch Size 的配置,它規定了每次最多從資料庫查詢多少條資料

3.假如你要查詢更多資料,它會在你執行 next()的時候,去查詢更多的資料。

4.就好比你去自動取款機取 10000 元,但取款機每次最多能取 2500 元,所以你要取 4 次才能把錢取完。只是對於 jdbc 來說,當你呼叫 next()的時候會自動幫你完成查詢工作。

5.這樣做的好處可以有效的防止記憶體溢位。


四.mybatis 邏輯分頁和物理分頁的區別是什麼?

1.邏輯分頁是一次性查詢很多資料,然後再在結果中檢索分頁的資料。這樣做弊端是需要消耗大量的記憶體、有記憶體溢位的風險、對資料庫壓力較大。

2.物理分頁是從資料庫查詢指定條數的資料,彌補了一次性全部查出的所有資料的種種缺點,比如需要大量的記憶體,對資料庫查詢壓力較大等問題。


五.mybatis 是否支援延遲載入?延遲載入的原理是什麼?

1.MyBatis 支援延遲載入。

2.什麼是延遲載入:延遲載入,也稱為懶載入,是指在進行關聯查詢時,按照設定延遲規則推遲對關聯物件的select查詢。延遲載入可以有效的減少資料庫壓力。MyBatis的延遲載入只是對關聯物件的查詢有延遲設定,對於主載入物件都是直接執行查詢語句的。

3.MyBatis 對關聯物件的載入型別

(1)直接載入:執行完對主載入物件的select語句,馬上執行對關聯物件的select查詢。

(2)侵入式延遲:執行對主載入物件的查詢時,不會執行對關聯物件的查詢。但當要訪問主載入物件的詳情時,就會馬上執行關聯物件的select查詢。(將關聯物件的詳情作為主載入物件的詳情的一部分出現)

(3)深度延遲:執行對主載入物件的查詢時,不會執行對關聯物件的查詢。訪問主載入物件的詳情時也不會執行關聯物件的select查詢。只有當真正訪問關聯物件的詳情時,才會執行對關聯物件的select查詢。

4.延遲載入的原理:呼叫的時候觸發載入,而不是在初始化的時候就載入資訊

例如:呼叫 a. getB(). getName(),這個時候發現 a. getB() 的值為 null,此時會單獨觸發事先儲存好的關聯 B 物件的 SQL,先查詢出來 B,然後再呼叫 a. setB(b),而這時候再呼叫 a. getB(). getName() 就有值了


六.說一下 mybatis 的一級快取和二級快取?

1.一級快取

(1)一級快取基於sqlSession預設開啟,在操作資料庫時需要構造SqlSession物件,在物件中有一個HashMap用於儲存快取資料。不同的SqlSession之間的快取資料區域是互相不影響的。

(2)一級快取的作用域是SqlSession範圍的,當在同一個sqlSession中執行兩次相同的sql語句時,第一次執行完畢會將資料庫中查詢的資料寫到快取(記憶體),第二次查詢時會從快取中獲取資料,不再去底層資料庫查詢,從而提高查詢效率。

(3)如果SqlSession執行了DML操作(增刪改),並且提交到資料庫,MyBatis則會清空SqlSession中的一級快取,這樣做的目的是為了保證快取中儲存的是最新的資訊,避免出現髒讀現象。

(4)當一個SqlSession結束後該SqlSession中的一級快取也就不存在了。

(5)關閉一級快取後,再次訪問,需要再次獲取一級快取,然後才能查詢資料,否則會丟擲異常。

2.二級快取

(1)二級快取是mapper級別的快取。使用二級快取時,多個SqlSession使用同一個Mapper的sql語句去操作資料庫,得到的資料會存在二級快取區域,它同樣是使用HashMap進行資料儲存。相比一級快取SqlSession,二級快取的範圍更大,多個Sqlsession可以共用二級快取,二級快取是跨SqlSession的。

(2)二級快取的作用域是mapper的同一個namespace。不同的sqlSession兩次執行相同的namespace下的sql語句,且向sql中傳遞的引數也相同,即最終執行相同的sql語句,則第一次執行完畢會將資料庫中查詢的資料寫到快取,第二次查詢會從快取中獲取資料,不再去底層資料庫查詢,從而提高效率。


七.mybatis 和 hibernate 的區別有哪些?

1.靈活性:MyBatis 更加靈活,自己可以寫 SQL 語句,使用起來比較方便。

2.可移植性:MyBatis 有很多自己寫的 SQL,因為每個資料庫的 SQL 可以不相同,所以可移植性比較差。

3.學習和使用門檻:MyBatis 入門比較簡單,使用門檻也更低。

4.二級快取:hibernate 擁有更好的二級快取,它的二級快取可以自行更換為第三方的二級快取。


八.mybatis 有哪些執行器(Executor)?

1.什麼是Statement

Statement 是 Java 執行數bai據庫操作的一個重要方法,用於du在已經建zhi立資料庫連線的基礎上dao,向資料庫傳送要執行的SQL語句。

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

(1)SimpleExecutor(單一的執行器):每執行一次update或select,就開啟一個Statement物件,用完立刻關閉Statement物件。

(2)ReuseExecutor(再次使用的執行器):執行update或select,以sql作為key查詢daoStatement物件,存在就使用,不存在就建立,用完後,不關閉Statement物件,而是放置於Map<String, Statement>內,供下一次使用。簡言之,就是重複使用Statement物件。

(3)BatchExecutor(批處理的執行器):執行update(沒有select,JDBC批處理不支援select),將所有sql都新增到批處理中(addBatch()),等待統一執行(executeBatch()),它快取了多個Statement物件,每個Statement物件都是addBatch()完畢後,等待逐一執行executeBatch()批處理。與JDBC批處理相同。

3.作用範圍:Executor的這些特點,都嚴格限制在SqlSession生命週期範圍內。


九.mybatis 分頁外掛的實現原理是什麼?

1.mybatis 分頁外掛:pageHelper

2.控制層程式碼

//1.在呼叫dao查詢前,先呼叫PageHelper的靜態方法
(1)PageHelper.startPage(pageNum, pageSize);
//2.呼叫dao查詢
(2)List<Product> products = productDao.findAllProduct();
//3.將查詢以構造方式存入到PageHelper為我們提供的分頁工具類PageInfo,返回
(3)PageInfo pageInfo = new PageInfo(products);

3.執行流程

(1)靜態方法startPage執行外掛會建立一個Page物件,儲存當前的頁碼和每頁條數。放在threadlocal變數中,和當前執行緒做繫結。

(2)在配置pageHelper時,需要在sqlSession中配置了PageInterceptor攔截器,它的作用是:

①sqlSession查詢前會被該攔截器攔截,
②攔截器會判斷該查詢是否需要分頁,如果不需要分頁,直接呼叫dao的sql進行執行,
③如果需要分頁,獲取dao執行的sql語句,根據當前使用的是哪個資料庫,拼接分頁的sql語句,執行改sql查詢得到分頁後的記錄結果集

(3)使用得到的記錄結果集 從threadlocal變數中取出page物件 把集合賦值給page物件 此時page物件已經包含pageNum pageSize total List記錄集合


十.mybatis 如何編寫一個自定義外掛?

1.MyBatis 允許使用外掛來攔截的方法

(1)Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) --執行sql

(2)ParameterHandler (getParameterObject, setParameters) --獲取、設定引數

(3)ResultSetHandler (handleResultSets, handleOutputParameters) --處理結果集

(4)StatementHandler (prepare, parameterize, batch, update, query) --記錄sql

2.自定義外掛原理

(1)Mybatis使用JDK的動態代理,為需要攔截的介面生成代理物件以實現介面方法攔截功能

(2)每當執行這4種介面物件的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,當然,只會攔截那些你指定需要攔截的方法。

(3)實現Mybatis的Interceptor介面並複寫intercept()方法,然後在給外掛編寫註解,指定要攔截哪一個介面的哪些方法即可。


十一:通常一個Xml對映檔案,都會寫一個Dao介面與之對應,請問,這個Dao介面的工作原理是什麼?Dao接口裡的方法,引數不同時,方法能過載嗎?

1.Dao介面詳解

(1)Dao介面就是人們常說的Mapper介面

(2)介面的全限名(路徑),就是對映檔案中的namespace的值

(3)介面的方法名,就是對映檔案中MappedStatement的id值

(4)介面方法內的引數,就是傳遞給sql的引數

(5)Mapper介面是沒有實現類的,當呼叫介面方法時,介面全限名+方法名拼接字串作為key值,可唯一定位一個MappedStatement

(6)Mybatis中,每一個<select>、<insert>、<update>、<delete>標籤,都會被解析為一個MappedStatement物件。

2.工作原理

(1)Dao介面的工作原理是JDK動態代理

(2)Mybatis執行時會使用JDK動態代理為Dao介面生成代理proxy物件

(3)代理物件proxy會攔截介面方法,轉而執行MappedStatement所代表的sql,然後將sql執行結果返回。

3.方法不能過載:因為是全限名+方法名的儲存和尋找策略。


十二:Mybatis是如何將sql執行結果封裝為目標物件並返回的?都有哪些對映形式?

1.使用<resultMap>標籤,逐一定義列名和物件屬性名之間的對映關係。

2.使用使用sql列的別名功能,將別名與resultType內產生對映關係,通過反射給物件的屬性逐一賦值並返回


十三:Xml對映檔案中,除了常見的select|insert|update|delete標籤之外,還有哪些標籤?

trim|where|set|foreach|if|choose|when|otherwise|bind等


十四:Mybatis對映檔案中,如果A標籤通過include引用了B標籤的內容,請問,B標籤能否定義在A標籤的後面,還是說必須定義在A標籤的前面?

1.被引用的B標籤可以定義在任何地方

2.原理

(1)Mybatis按順序解析A標籤。

(2)當發現A標籤引用了B標籤,但是B標籤尚未解析到,尚不存在。Mybatis會將A標籤標記為未解析狀態,然後繼續解析餘下的標籤,包括B標籤。

(3)待所有標籤解析完畢,Mybatis會重新解析那些被標記為未解析的標籤。

(4)此時再解析A標籤時,B標籤已經存在,A標籤也就可以正常解析完成了。


十五:簡述Mybatis的Xml對映檔案和Mybatis內部資料結構之間的對映關係?

1.Mybatis將所有Xml配置資訊都封裝到All-In-One重量級物件Configuration內部。

2.在Xml對映檔案中,<parameterMap>標籤會被解析為ParameterMap物件,其每個子元素會被解析為ParameterMapping物件。

3.<resultMap>標籤會被解析為ResultMap物件,其每個子元素會被解析為ResultMapping物件。

4.每一個<select>、<insert>、<update>、<delete>標籤均會被解析為MappedStatement物件,標籤內的sql會被解析為BoundSql物件。