天天看點

購物網站和秒殺系統實作技術 - 懵懂的菜鳥

購物網站和秒殺系統實作技術

我們需要兩個子產品,一個背景Admin子產品,一個前台Home子產品,利用ThinkPhp架構,自動生成MVC架構如圖6-2所示。

任何一個表單的操作,都需要前端驗證和背景驗證,前端驗證是為了使用者體驗,使用javascript,背景驗證是為了資料的完整性,使用php,最好的方法,是結合二者,就是ajax了。圖檔上傳的部分,使用tp自帶的上傳類。

6.3 秒殺系統

秒殺系統其實是針對庫存做的系統。使用者成功秒殺商品,對于我們系統的操作就是減庫存和記錄使用者的購買明細。使用者的購買明細包括記錄誰購買成功、購買成功的時間和付款資訊。而對于減庫存操作,需要考慮到以下兩個問題:

(1)若是使用者成功秒殺商品,我們記錄了其購買明細,卻沒有減庫存。會導緻商品的超賣。

(2)減了庫存卻沒有記錄使用者的購買明細,導緻商品的少賣。

對于上述兩個問題,可以通過MySQL内置的事務機制進行處理,它可以準确的幫我們完成減庫存和記錄使用者購買明細的過程。

對于秒殺系統,我們隻是實作秒殺的一些功能:

(1)秒殺接口的暴露。

(2)執行秒殺的操作。

(3)相關查詢,比如說清單查詢,詳情頁查詢。

秒殺系統包括包括三個子產品的設計,DAO層、Service層和Web層的設計,另外考慮到系統高并發的問題,進而設計了系統高并發的處理。在系統設計之前,為了更好地了解系統的開發過程,對相關技術進行描述。

6.3.2 相關軟體包安裝

用Maven建立我們的項目seckill,然後使用IDEA打開該項目。在 main包下進行我們項目的代碼編寫及相關配置檔案,test包下進行我們項目的測試。

秒殺系統的servlet版本為3.1,相關的第三發jar包通過pom檔案添加,

6.3.2 DAO層

首先需要建立秒殺庫存表和秒殺成功明細表,如下所示:

基于MyBatis來實作我們設計的Dao層接口。首先需要配置我們的MyBatis,在resources包下建立MyBatis全局配置檔案mybatis-config.xml檔案。

配置檔案建立好後我們需要關注的是Dao接口該如何實作,mybatis為我們提供了mapper動态代理開發的方式為我們自動實作Dao的接口。在mapper包下建立對應Dao接口的xml映射檔案,裡面用于編寫我們操作資料庫的sql語句,SeckillDao.xml和SuccessKilledDao.xml。

MyBatis和Spring的整合,整合目标:

(1)更少的編碼:隻寫接口,不寫實作類。

(2)更少的配置:别名、配置掃描映射xml檔案、dao實作。

(3)足夠的靈活性:自由定制SQL語句、自由傳結果集自動指派。

在spring包下建立一個spring-dao.xml,用于配置dao層對象的配置檔案,在resources包下建立jdbc.properties.xml,用于配置資料庫的連接配接資訊,配置如下。

6.3.3 Service層

在Dao層我們隻完成了針對表的相關操作,包括寫了接口方法和映射檔案中的sql語句,并沒有編寫邏輯的代碼,例如對多個Dao層方法的拼接,當我們使用者成功秒殺商品時我們需要進行商品的減庫存操作(調用SeckillDao接口)和增加使用者明細(調用SuccessKilledDao接口),這些邏輯我們都需要在Service層完成。Dao層隻進行資料的通路操作,接下來我們便進行Service層代碼的編寫。秒殺Service接口設計如下:

(1)建立service包用于存放我們的Service接口和其實作類。

(2)建立exception包用于存放service層出現的異常,例如重複秒殺商品異常、秒殺已關閉等異常。

(3)建立dto包作為傳輸層, 用于完成web和service層的資料傳遞。

(4)建立entity包用于業務資料的封裝。

在dto包中建立Exposer.java,用于封裝秒殺的位址資訊。SeckillExecution.java,用于判斷秒殺是否成功,成功就傳回秒殺成功的所有資訊(包括秒殺的商品id、秒殺成功狀态、成功資訊、使用者明細),失敗就抛出一個我們允許的異常(重複秒殺異常、秒殺結束異常)。

然後需要在exception包下建立我們在秒殺業務過程中允許的異常,RepeatKillException.java用于處理重複的秒殺異常;SeckillCloseException.java用于處理秒殺關閉異常;SeckillException.java用于處理秒殺相關業務的異常。

在實作類SeckillServiceImpl.java中,我們用枚舉的方式将異常函數中傳回的常量進行封裝,在enums包下建立一個枚舉類型SeckillStatEnum.java,用于傳回state和stateInfo這兩個參數的相關資料。

使用Spring托管Service依賴配置:

在spring包下建立一個spring-service.xml檔案,然後采用注解的方式将Service的實作類加入到Spring IOC容器中,然後在Service實作類的方法中,在需要進行事務聲明的方法上加上事務的注解,配置如下。

6.3.4 Web層

秒殺系統Web層主要涉及前端互動設計、Restful:url滿足Restful設計規範、Spring MVC、bootstrap+jquery這四個方面的開發。秒殺系統的前端互動流程設計如下圖6-3所示。

購物網站和秒殺系統實作技術 - 懵懂的菜鳥

圖6-3 前端互動流程

整合配置Spring MVC架構:

在web.xml中進行我們前端控制器DispatcherServlet的配置,配置springMVC需要加載的配置檔案spring-dao.xml,spring-service.xml和spring-web.xml,詳細配置如下。

完成Spring MVC的相關配置後,接下來就要基于Restful接口實作項目中的Controller開發。Controller中的每一個方法都對應我們系統中的一個資源URL,其設計應該遵循Restful接口的設計風格。在web包下建立一個SeckillController.java,内容如表6-11所示。

json資料的一個Vo類,即SeckillResult.java,在dto包中建立它,内容如下。

6.3.5 高并發的優化

秒殺系統面臨着如下問題:

(1)無法使用cdn緩存,因為系統邏輯不可能放在cdn中。

(2)後端緩存困難:庫存問題,因為運用到了mysql事務操作(設定聯合主鍵)。

(3)一行資料競争:熱點商品,因為多個使用者同時對資料庫某條資料進行操作。

秒殺系統的優化方案:

(1)前端控制:暴露接口,按鈕防重複送出。

(2)動靜态資料分離:cdn緩存,後端Redis緩存。

(3)事務競争優化:減少事務鎖時間,把用戶端邏輯放在mysql服務端,避免網絡延遲和GC的影響。 GC(Garbage Collection)垃圾回收機制

使用Redis優化位址暴露接口,在dao包下建立一個cache包,然後建立一個RedisDao.java函數,在spring-dao.xml中配置redisdao構造器。

針對網絡延遲和GC導緻的并發問題,使用存儲過程,将整個事務放在mysql端完成,秒殺存儲過程實作如下。

最後,在ServiceService.java中建立存儲執行秒殺操作的函數,在SeckillDao.java實作該接口,在SeckillDao.xml中使用mybatis調用存儲過程,在服務端的SeckillServiceImpl.java完成配置即可。

購物網站和秒殺系統實作技術 - 懵懂的菜鳥