前兩個項目採用的是ssh架構搭建的,最近的項目採用的是ssm架構搭建的。在實際開發中,我覺得這兩個架構,他們最大的區別在於hibernate與mybatis的區別。
Hibernate與mybatis相比較,mybatis更為輕便、靈活,容易掌握。mybatis可以把sql語句從java代碼中分離了出來,放在了設定檔中書寫,大大降低裡java代碼與SQL語句的耦合度,更容易對sql語句操作,重要的是mybatis還可以書寫動態sql語句,但mybatis也存在一些缺陷,比如mybatis本身的緩衝機制沒有hibernate那麼完善,hibernate除了本身有良好的緩衝機制,還可以使用第三方緩衝。Hibernate較完整的封裝了JDBC,但學起來要比mybatis更困難一些。Hibernate的DAO層開發比MyBatis簡單,對對象的維護和緩衝要比MyBatis好。
(springmvc與Struts的區別:springmvc是方法層級的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,參數的傳遞是直接注入到方法中的,是該方法專屬的。
struts2是類層級的攔截, 一個類對應一個request上下文, struts是在接受參數的時候,可以用屬性來接受參數, 這就說明參數是讓多個方法共用的,這也就無法用註解或其他方式標識其所屬方法了)。
該商城是一個綜合性的B2C平台,主要針對女性消費者,主要銷售女性化妝品,首飾,服裝等女性用品。商家入駐商城銷售自家的產品,並且可以得到商城提供的各種服務。
在整個項目中,我們採用的是nginx+tomcat來部署的(面試官會可能問nginx是誰來部署的。如何部署的。Nginx的執行流程,優點),nginx一方面做載入靜態資源的伺服器,另一方面來做反向 Proxy和負載平衡。因為該項目需要在多個環境中運行,我們利用了nginx的反向 Proxy解決了不同環境同系統訪問地址不統一帶來的問題。
因為整個項目實現的功能較多, 所以採用分布式的架構設計,整個項目包括後台管理系統、前台系統、訂單系統、登入系統、搜尋系統、購物車系統等,這樣做的好處是使每個功能模組獨立出來,降低了各系統之間的耦合度,增刪一個功能不會影響其他功能模組。
因為項目是採用分布式架構設計的,各模組之間是相互獨立的,而各模組的訪問路徑又是不同的,所以當跨域請求資料的時候會遇到跨域受限的問題。比如當使用者首次訪問該網站首頁時,首頁頁面會非同步請求後台管理系統載入商品的類目,這是就會出現跨域受限的問題,以前開發時,如果在本模組內,我們是通過ajax非同步請求資料的,但Ajax不支援跨域,所以用ajax無法解決跨域請求資料的問題。最後我們使用的是jsonp來解決這個問題的。jsonp通過script標籤的src可以跨域請求的特性,載入資源,將載入的資源(通過一個方法名將資料進行包裹)當做是js指令碼解析,定義一個回呼函數(是怎麼實現的。),擷取傳入的資料。我們使用jsonp是因為Jsonp的相容性比較好,並且在請求完畢後可以通過callback的方式回傳結果。但jsonp有一個缺點是只支援get請求而不支援post等其他類型的http請求。
這樣我們解決了瀏覽器訪問當前頁面去載入後台系統資料出現的跨域問題,但是另一個問題又來了,其他系統該如何得到調用後台系統的資料呐。我們想可以發送http請求來訪問後台資料,我們想到的是使用httpclient來解決此問題,因為httpclient可以使用java代碼類比瀏覽器發送http請求(get方法如何傳遞參數。定義uribuilder對象,在uribuilder裡設定參數,以key和value,都是string類型的,然後將uribuilder放到uri中,在後將uri講給httpget請求。Post方法如果傳輸資料。類比表單提交,將資料封裝到list集合中,然後將集合資料放入構造的表單實體中,在將表單實體請求放到httppost對象中)。向外拋出一個介面,執行過程是:1、建立httpclient對象2、構建請求對象post ,get請求3、如果有參數,就去構造請求參數
3.1 get
使用uribuilder去構造請求參數
3.2 post
構建表單實體,把表單實體放入到 post請求對象中。
4、執行請求 ,並且接受響應
5、處理響應結果
6. 釋放串連。無論執行方法是否成功,都必須釋放串連。
HttpClient實現認為是安全執行緒的。
每次串連發起Http請求的時候都會重建立立串連(經曆3次握手),用完就會關閉串連(4次揮手),這樣會消耗很多時間,所有我們採用了串連池。如果不採用串連池,每次串連都會開啟一個連接埠,在大並發的情況下系統的連接埠資源很快就會被用完,導致無法建立新的串連。
像項目中首頁的大廣告和商品類目這些不需要經常修改的資料,如果使用者每次重新整理頁面的時候都要去資料庫中查詢,這樣會浪費資源和增加資料庫的壓力。所以我們想當把這些資料添加到一個緩衝中,使用者去訪問的時候,先去緩衝中命中,如果命中失敗,再去資料庫中查詢,然後把查詢到的資料添加到緩衝中。目前比較主流的緩衝技術有Redis和Memcached,單純從快取命中的角度來說,Memcached要高一些,可Redis和Memcache的差距其實並不大,但Redis提供的功能更加強大一些,讀寫速度也很快。所以我們選用了redis來快取資料。Redis把資料以key—value的形式緩衝到記憶體中,並提供了多種資料存放區類型(string,set,list,hash等),還自身提供了持久化功能(2種),還可以把資料備份到磁碟中(Redis的SAVE命令用於建立當前 Redis 資料庫的備份),防止redis宕機時的資料丟失。(會周期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了master-slave(主從)同步)。我們使用的是spring與jedis整合的用戶端,可以利用jedis做分區式叢集,解決了redis記憶體受限的問題。
之前實現的登入和註冊是在同一個tomcat內部完成,而現在系統架構是每一個系統都是由一個團隊進行維護,每個系統都是單獨部署運行一個單獨的tomcat,所以,不能將使用者的登入資訊儲存到session中(多個tomcat的session是不能共用的)(session共用。),所以我們需要一個單獨的系統來維護使用者的登入資訊。我們是這樣做的,使用者去登入頁面登入,去資料庫查詢是否有該使用者,如果沒有提示使用者,如果有就把使用者資訊儲存到redis中,並產生一個token儲存到cookie中,
在後台管理系統中採用了Maven的多模組化的管理,其中採用了水平切分的方式(垂直與水平劃分的區別:垂直:功能模組明確,層次不夠清晰,代碼重用性差。水平:層次清晰,代碼重用性高,獨立維護。),將各層分層開發,這樣做的好處是代碼重用性高,層次清晰,易於獨立維護。系統內部介面調用採用Httpclient,介面提供端採用RESTful方式的介面定義(一種軟體架構風格,設計風格而不是標準,只是提供了一組設計原則和約束條件),系統之間的通知機制採用MQ的方式,使用RabbitMQ的實現,使用了RabbitMQ的訊息訂閱模式的訊息機制;部署方面,採用了Nginx+tomcat的模式,其中nginx的作用一方面是做反向 Proxy、負載平衡、另一方面是做圖片等靜態資源的伺服器;
在此項目中我主要負責後台管理模組,主要實現商品管理和商品規格參數管理,對商品和商品規格進行CRUD操作。;在實現前台調用後台資料時,為了實現系統間的調用,便使用了httpclient技術來實現此功能,在後台提供了需要調用的介面。(httpclient介紹,工作原理,優缺點)。如果在後台對商品進行操作,為了使前台資料與後台資料實現同步,我們使用了RabbitMQ訊息佇列機制實現商品同步功能(RabbitMQ介紹,工作原理,優缺點);
在此項目中,我還參與了購物車模組的開發。在開發這個模組時候,我們考慮了會員在未登入和登入兩種情況下把商品加入購物車,後台如何該儲存商品資訊。
在使用者商品詳情頁點擊加入購物車的時候,我們用了登入攔截器來判斷使用者是否登入;購物車首先標識要唯一,因為每個帳號要對應一個購物車,在登入狀態下,我們可以直接將資料儲存到資料庫中,使用使用者的id表示自己購買的商品,但是如果在未登入狀態下呢,或者對購車訪問量大的時候,這個就存在弊端,因為這樣高速的讀寫資料庫,會對資料庫的壓力比較大,在這裡我們就看看如何用Redis和RabbitMQ解決這個問題。
一:登入狀態下添加商品到購物車
此時購物車是對應一個使用者,很簡單,就是將商品的資料插入資料庫中即可,但是如果讀寫頻繁的時候,就存在壓力問題,此時我們可以使用Redis擔任讀的部分功能。
在向資料庫中插入資料的時候,使用RabbitMQ發送訊息,然後有一個訊息系統監聽訊息,將RabbitMQ中訊息內容(插入資料庫中的商品資料)儲存到Redis中,但是此時Redis中我們該用什麼儲存結構,在Redis中儲存結構有很多種,這裡我們使用hash結構(介紹一下是如何利用hash結構儲存商品資料的),在使用者查詢自己的購物車資料的時候,就不要到資料庫中查詢,而是直接從redis中將資料拿出來即可,這樣資料庫的讀壓力就被Redis分擔出去了。
二:未登入下加入購物車,登入下合并購物車
在未登入狀態下,沒有指定的使用者,此時購物車應該怎麼分配,資料把偶才能在什麼位置,這個其實也不難,我們可以將資料臨時儲存到Redis中,並不插入資料庫中,因為此時沒有對應的使用者,Redis產生一個唯一的outerKey,儲存到cookie中,每次添加商品,帶上這個cookie,這樣就保證每次加入同一個購物車,這個資料會被儲存一段時間,當使用者登入的時候,我們該如何將未登入狀態下的購車和登入狀態下的購車資料合併呢。這個就需要使用到訊息了,我們可以發送一個訊息給後台系統,將未登入狀態下的outerKey傳遞給後台系統,後台系統到Redis中查詢到未登入狀態下的購物車,將購物車中的資料插入到資料庫中,和之前登入狀態下的購車資料合併,重新緩衝到Redis中,此時緩衝到Redis中的購物車是和未登入狀態不同的,因為這個緩衝的購物車是有主人的,未登入狀態下緩衝的臨時購物車就儲存到了登入使用者的購物車。
(自己設兩個自問自答的問題)
資料庫也可以做讀寫分離,為什麼要使用Redis擔任讀呢,直接使用讀寫分離不就可以了嗎。
資料庫的讀寫分離的確可以解決問題,但是像Redis這種非關係型資料庫比較明顯的優點就是資料處理效率高,讀寫分離和Redis的效率相比較來說,個人感覺還是使用Redis可靠。
Redis擔任讀的問題,當像雙11這種大量訪問的情況下,Redis會不會崩潰。
這個問題我也想過,這個我們可以考慮使用Redis的叢集,這樣就可以解決大部分的問題。