MVC(SpringMVC)與ORM(MyBatis)

2020-09-19 12:04:19

MVC

MVC 模型,它包含了 Model(模型),View(檢視)和 Controller(控制器)。是針對表現層的設計模型,MVC是一種設計模式
MVC的原理圖: 在這裡插入圖片描述M-Model 模型(完成業務邏輯:有javaBean構成,service+dao+entity)
V-View 檢視(做介面的展示 jsp,html……)
C-Controller 控制器(接收請求—>呼叫模型—>根據結果派發頁面)

MVC 模型的優勢
第一:清晰的職責劃分。
第二:每個元件作用獨立。有利於程式碼的重用。
第三:由於可重用性強,所以後期維護起來方便。
第四:任何專案都適用

MVC 模型的弊端
任何事情都是有其兩面性,MVC 模型也並不是全方位優秀的設計模型。它的弊端體現在:
第一:展示資料響應速度慢
第二:對開發人員的要求高,需要合理的設計和嚴謹的架構。
第三:非同步互動並不方便

基於非同步請求的 MVVM模式
在這裡插入圖片描述它全稱是 Model View VielModel。是針對 mvc 模型的再次改良,不過只改良了展示資料的部分。(Controller 的再次優化交給了框架,Model 部分已經無需再優化)
在上一小節,我們提出了非同步互動不變的弊端,這主要是在非同步展示資料時,javascript 的邏輯處理和資料顯示交織在了一起,當我們想進行調整時,需要閱讀大量的程式碼,給後期維護造成了影響。而 MVVM 它把 javascript的邏輯處理和資料展示分開,可以讓使用者在後期維護時,針對不同的需求進行調整。例如:如果是邏輯部分需要處理,則修改邏輯部分程式碼。如果是資料顯示位置需要調整,則修改展示部分的程式碼,使前端展示更加靈活,也更加合理。

SpringMVC

springMVC流程:
(1):⽤戶請求傳送給DispatcherServlet,DispatcherServlet調⽤HandlerMapping處理器對映器;
(2):HandlerMapping根據xml或註解找到對應的處理器,⽣成處理器物件返回DispatcherServlet;
(3):DispatcherServlet會調⽤相應的HandlerAdapter;
(4):HandlerAdapter經過適配調⽤具體的處理器去處理請求,⽣成ModelAndView返回給DispatcherServlet
(5):DispatcherServlet將ModelAndView傳給ViewReslover解析⽣成View返回DispatcherServlet;
(6):DispatcherServlet根據View進⾏渲染檢視;
在這裡插入圖片描述

->DispatcherServlet->HandlerMapping->Handler ->DispatcherServlet->HandlerAdapter處理handler->ModelAndView ->DispatcherServlet->ModelAndView->ViewReslover->View ->DispatcherServlet->返回給客戶

元件:
1、前端控制器DispatcherServlet(不需要工程師開發),由框架提供
作用:接收請求,響應結果,相當於轉發器,中央處理器。有了dispatcherServlet減少了其它元件之間的耦合度。
使用者請求到達前端控制器,它就相當於mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它呼叫其它元件處理使用者的請求,dispatcherServlet的存在降低了元件之間的耦合性。
2、處理器對映器HandlerMapping(不需要工程師開發),由框架提供
作用:根據請求的url查詢Handler
HandlerMapping負責根據使用者請求找到Handler即處理器,springmvc提供了不同的對映器實現不同的對映方式,例如:組態檔方式,實現介面方式,註解方式等。
3、處理器介面卡HandlerAdapter
作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler
通過HandlerAdapter對處理器進行執行,這是介面卡模式的應用,通過擴充套件介面卡可以對更多型別的處理器進行執行。
4、處理器Handler(需要工程師開發)
注意:編寫Handler時按照HandlerAdapter的要求去做,這樣介面卡才可以去正確執行Handler
Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的使用者請求進行處理。
由於Handler涉及到具體的使用者業務請求,所以一般情況需要工程師根據業務需求開發Handler。
5、檢視解析器View resolver(不需要工程師開發),由框架提供
作用:進行檢視解析,根據邏輯檢視名解析成真正的檢視(view)
View Resolver負責將處理結果生成View檢視,View Resolver首先根據邏輯檢視名解析成物理檢視名即具體的頁面地址,再生成View檢視物件,最後對View進行渲染將處理結果通過頁面展示給使用者。
springmvc框架提供了很多的View檢視型別,包括:jstlView、freemarkerView、pdfView等。
一般情況下需要通過頁面標籤或頁面模版技術將模型資料通過頁面展示給使用者,需要由工程師根據業務需求開發具體的頁面。
6、檢視View(需要工程師開發jsp…)
View是一個介面,實現類支援不同的View型別(jsp、freemarker、pdf…)

核心架構的具體流程步驟如下:
1、首先使用者傳送請求——>DispatcherServlet,前端控制器收到請求後自己不進行處理,而是委託給其他的解析器進行處理,作為統一存取點,進行全域性的流程控制;
2、DispatcherServlet——>HandlerMapping, HandlerMapping 將會把請求對映為
HandlerExecutionChain 物件(包含一個Handler 處理器(頁面控制器)物件、多個
HandlerInterceptor 攔截器)物件,通過這種策略模式,很容易新增新的對映策略;
3、DispatcherServlet——>HandlerAdapter,HandlerAdapter 將會把處理器包裝為介面卡,從而支援多種型別的處理器,即介面卡設計模式的應用,從而很容易支援很多型別的處理器;
4、HandlerAdapter——>處理器功能處理方法的呼叫,HandlerAdapter 將會根據適配的結果呼叫真正的處理器的功能處理方法,完成功能處理;並返回一個ModelAndView 物件(包含模型資料、邏輯檢視名);
5、ModelAndView的邏輯檢視名——> ViewResolver, ViewResolver 將把邏輯檢視名解析為具體的View,通過這種策略模式,很容易更換其他檢視技術;
6、View——>渲染,View會根據傳進來的Model模型資料進行渲染,此處的Model實際是一個Map資料結構,因此很容易支援其他檢視技術;
7、返回控制權給DispatcherServlet,由DispatcherServlet返回響應給使用者,到此一個流程結束。下邊兩個元件通常情況下需要開發:
Handler:處理器,即後端控制器用controller表示。
View:檢視,即展示給使用者的介面,檢視中通常需要標籤語言展示模型資料

SpringMVC怎麼樣設定重定向和轉發的?
(1)轉發:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"
SpringMVC常用的註解有哪些?
@RequestMapping:用於處理請求 url 對映的註解,可用於類或方法上。用於類上,則表示類中的所有響應請求的方法都是以該地址作為父路徑。
@RequestBody:註解實現接收http請求的json資料,將json轉換為java物件。
@ResponseBody:註解實現將conreoller方法返回物件轉化為json物件響應使用者。

ORM

通過 Java 語言連線並運算元據庫的技術或方式已經有很多了,例如:JDBC,
Hibernate,MyBatis,TopLink 等等。其中 JDBC 是 Java 原生的 API,支援連線並操作各種關係型資料庫。JDBC 作為 Java 原生 API,有優點,也有缺點,這裡主要說一下缺點:

  1. 編碼繁瑣,效率低
  2. 資料庫連線的建立和釋放比較重複,也造成了系統資源的浪費
  3. 大量寫死,缺乏靈活性,不利於後期維護
  4. 引數的賦值和資料的封裝全是手動進行

正是因為 JDBC 存在著各種問題,所以才導致很多持久層框架應運而生,例如:Hibernate
和 MyBatis,這兩個都是目前比較流行的持久層框架,都對 JDBC 進行了更高階的封裝和優化。

第一類:著重對 JDBC 進行 API 層的抽取和封裝,以及功能的增強,典型代表是 Apache 的DbUtils。程式設計師在使用 DbUtils 時仍然需要編寫 sql 語句並手動進行資料封裝,但是 API 的使用比 JDBC方便了很多。

第二類:借鑑物件導向的思想,讓程式設計師以操作物件的方式運算元據庫,無需編寫 sql 語句,典型代表是 ORM。ORM(Object Relational Mapping)吸收了物件導向的思想,把對 sql 的操作轉換為物件的操作,從而讓程式設計師使用起來更加方便和易於接受。這種轉換是通過物件和表之間的後設資料對映實現的,這是實現 ORM 的關鍵,如下圖所示:
在這裡插入圖片描述由於類和表之間以及屬性和欄位之間建立起了對映關係,所以,通過 sql 對錶的操作就
可以轉換為物件的操作,程式設計師從此無需編寫 sql 語句,由框架根據對映關係自動生成,這
就是 ORM 思想。
目前比較流行的 Hibernate 和 MyBatis 都採用了 ORM 思想,一般我們把 Hibernate 稱之
為全自動的 ORM 框架,把 MyBatis 稱之為半自動的 ORM 框架。

什麼是MyBatis
(1)Mybatis是一個半ORM(物件關係對映)框架,它內部封裝了JDBC,開發時只需要關注SQL語句本身,不需要花費精力去處理載入驅動、建立連線、建立statement等繁雜的過程。程式設計師直接編寫原生態sql,可以嚴格控制sql執行效能,靈活度高。
(2)MyBatis 可以使用 XML 或註解來設定和對映原生資訊,將 POJO對映成資料庫中的記錄,避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。
(3)通過xml 檔案或註解的方式將要執行的各種 statement 設定起來,並通過java物件和 statement中sql的動態引數進行對映生成最終執行的sql語句,最後由mybatis框架執行sql並將結果對映為java物件並返回。(從執行sql到返回result的過程)。
MyBatis的優點和缺點
優點:
(1)基於SQL語句程式設計,相當靈活,不會對應用程式或者資料庫的現有設計造成任何影響,SQL寫在XML裡,解除sql與程式程式碼的耦合,便於統一管理;提供XML標籤,支援編寫動態SQL語句,並可重用。
(2)與JDBC相比,減少了50%以上的程式碼量,消除了JDBC大量冗餘的程式碼,不需要手動開關連線;
(3)很好的與各種資料庫相容(因為MyBatis使用JDBC來連線資料庫,所以只要JDBC支援的資料庫MyBatis都支援)。
(4)能夠與Spring很好的整合;
(5)提供對映標籤,支援物件與資料庫的ORM欄位關係對映;提供物件關係對映標籤,支援物件關係元件維護。

缺點
(1)SQL語句的編寫工作量較大,尤其當欄位多、關聯表多時,對開發人員編寫SQL語句的功底有一定要求。
(2)SQL語句依賴於資料庫,導致資料庫移植性差,不能隨意更換資料庫。

MyBatis 的 ORM 實現原理在這裡插入圖片描述

在這裡插入圖片描述
在這裡插入圖片描述MyBatis 是支援客製化化 SQL、儲存過程以及高階對映的優秀的持久層框架,其主要就完成2件事情:

  • 封裝JDBC操作
  • 利用反射打通Java類與SQL語句之間的相互轉換

MyBatis的主要設計目的就是讓我們對執行SQL語句時對輸入輸出的資料管理更加方便,所以方便地寫出SQL和方便地獲取SQL的執行結果才是MyBatis的核心競爭力。

流程

1 載入設定:設定來源於兩個地方,一是組態檔,一是Java程式碼的註解,將SQL的設定資訊載入成為一個個MappedStatement物件(包括了傳入引數對映設定、執行的SQL語句、結果對映設定),儲存在記憶體中。
2 SQL解析:當API介面層接收到呼叫請求時,會接收到傳入SQL的ID和傳入物件(可以是Map、JavaBean或者基本資料型別),Mybatis會根據SQL的ID找到對應的MappedStatement,然後根據傳入引數物件對MappedStatement進行解析,解析後可以得到最終要執行的SQL語句和引數。
3 SQL執行:將最終得到的SQL和引數拿到資料庫進行執行,得到運算元據庫的結果。
4 結果對映:將運算元據庫的結果按照對映的設定進行轉換,可以轉換成HashMap、JavaBean或者基本資料型別,並將最終結果返回。

Mybatis原理

  • sqlsessionFactoryBuilder⽣成sqlsessionFactory(單例)
  • ⼯⼚模式⽣成sqlsession執⾏sql以及控制事務
  • Mybatis通過動態代理使Mapper(sql對映器)接⼝能運⾏起來即為接⼝⽣成代理物件將sql查詢到結果對映成pojo

sqlSessionFactory構建過程

  • 解析並讀取設定中的xml建立Configuration物件 (單例)
  • 使⽤Configruation類去建立sqlSessionFactory(builder模式)

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

#{}是預編譯處理,KaTeX parse error: Expected 'EOF', got '#' at position 21: …串替換。 Mybatis在處理#̲{}時,會將sql中的#{}替…{}時,就是把${}替換成變數的值。
使用#{}可以有效的防止SQL隱碼攻擊,提高系統安全性。

當實體類中的屬性名和表中的欄位名不一樣 ,怎麼辦 ?
第1種: 通過在查詢的sql語句中定義欄位名的別名,讓欄位名的別名和實體類的屬性名一致。
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
第2種: 通過來對映欄位名和實體類屬性名的一一對應的關係。

Mybatis是如何進行分頁的?分頁外掛的原理是什麼?
Mybatis使用RowBounds物件進行分頁,它是針對ResultSet結果集執行的記憶體分頁,而非物理分頁。可以在sql內直接書寫帶有物理分頁的引數來完成物理分頁功能,也可以使用分頁外掛來完成物理分頁。
分頁外掛的基本原理是使用Mybatis提供的外掛介面,實現自定義外掛,在外掛的攔截方法內攔截待執行的sql,然後重寫sql,根據dialect方言,新增對應的物理分頁語句和物理分頁引數。
Mybatis是如何將sql執行結果封裝為目標物件並返回的?都有哪些對映形式?
第一種是使用標籤,逐一定義資料庫列名和物件屬性名之間的對映關係。
第二種是使用sql列的別名功能,將列的別名書寫為物件屬性名。
有了列名與屬性名的對映關係後,Mybatis通過反射建立物件,同時使用反射給物件的屬性逐一賦值並返回,那些找不到對映關係的屬性,是無法完成賦值的。

MyBatis實現一對一有幾種方式?具體怎麼操作的?
有聯合查詢和巢狀查詢,聯合查詢是幾個表聯合查詢,只查詢一次, 通過在resultMap裡面設定association節點設定一對一的類就可以完成;
巢狀查詢是先查一個表,根據這個表裡面的結果的 外來鍵id,去再另外一個表裡面查詢資料,也是通過association設定,但另外一個表的查詢通過select屬性設定。
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的一級、二級快取:

預設情況下⼀級快取是開啟的,⽽且是不能關閉的。

  • ⼀級快取是指 SqlSession 級別的快取 原理:使⽤的資料結構是⼀個 map,如果兩次中間出現commit 操作 (修改、新增、刪除),本 sqlsession 中的⼀級快取區域全部清空
  • ⼆級快取是指可以跨 SqlSession 的快取。是 mapper 級別的快取; 原理: 是通過 CacheExecutor實現的。CacheExecutor其實是 Executor 的代理物件

1)一級快取: 基於 PerpetualCache 的 HashMap 本地快取,其儲存作用域為 Session,當 Sessionflush 或 close 之後,該 Session 中的所有 Cache 就將清空,預設開啟一級快取。
2)二級快取與一級快取其機制相同,預設也是採用 PerpetualCache,HashMap 儲存,不同在於其儲存作用域為 Mapper(Namespace),並且可自定義儲存源,如 Ehcache。預設不開啟二級快取,要開啟二級快取,使用二級快取屬性類需要實現Serializable序列化介面(可用來儲存物件的狀態),可在它的對映檔案中設定 ;
3)對於快取資料更新機制,當某一個作用域(一級快取 Session/二級快取Namespaces)的進行了C/U/D操作後,預設該作用域下所有 select 中的快取將被 clear 掉並重新更新,如果開啟了二級快取,則只根據設定判斷是否重新整理。