做者:nnngu
項目源代碼:https://github.com/nnngu/nguSeckilljava
這是一個整合IDEA+Maven+SSM框架的高併發的商品秒殺項目。咱們將分爲如下幾篇文章來進行詳細的講解:git
以IntelliJ IDEA爲例,點擊File > New > Project > Maven
github
而後點擊Next繼續;web
填寫相關信息,點擊Next;spring
最後點擊Finish,完成建立。sql
若是右下角彈出下面這個提示,點擊Enable Auto-Import
數據庫
點擊File > Project Structure
apache
步驟1mybatis
步驟2併發
步驟3
步驟4
步驟5
步驟6
步驟7
步驟8
Maven項目建立好了,接下來咱們要添加一些jar包的依賴,也就是在pom.xml
中添加各類開源組件的座標。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.nnngu</groupId> <artifactId>nguSeckill</artifactId> <version>1.0-SNAPSHOT</version> <!-- 代碼省略,請參照項目的源代碼 --> ... ...
完整的代碼,請查看項目裏的pom.xml
文件
到此,咱們項目的初始化工做完成。
秒殺系統業務流程以下:
由圖能夠發現,整個系統實際上是針對庫存作的系統。用戶成功秒殺商品,對於咱們系統的操做就是:
減庫存
記錄用戶的購買明細。下面看看咱們用戶對庫存的業務分析:
記錄用戶的秒殺成功信息,咱們須要記錄:一、誰購買成功了。二、購買成功的時間/有效期。三、付款/發貨信息。這些數據組成了用戶的秒殺成功信息,也就是用戶的購買行爲。
爲何咱們的系統須要事務?看以下這些故障:一、如果用戶成功秒殺商品咱們記錄了其購買明細卻沒有減庫存。致使商品的超賣。二、減了庫存卻沒有記錄用戶的購買明細。致使商品的少賣。對於上述兩個故障,如果沒有事務的支持,損失最大的無疑是咱們的用戶和商家。在MySQL中,它內置的事務機制,能夠準確的幫咱們完成減庫存和記錄用戶購買明細的過程。
MySQL實現秒殺的難點分析:當用戶A秒殺id爲10的商品時,此時MySQL須要進行的操做是:一、開啓事務。二、更新商品的庫存信息。三、添加用戶的購買明細,包括用戶秒殺的商品id以及惟一標識用戶身份的信息如電話號碼等。四、提交事務。若此時有另外一個用戶B也在秒殺這件id爲10的商品,他就須要等待,等待到用戶A成功秒殺到這件商品而後MySQL成功的提交了事務他才能拿到這個id爲10的商品的鎖從而進行秒殺,而同一時間是不可能只有用戶B在等待,確定是有不少不少的用戶都在等待拿到這個行級鎖。秒殺的難點就在這裏,如何高效的處理這些競爭?如何高效的完成事務?在後面第4個模塊如何進行高併發的優化爲你們講解。
咱們這個系統須要完成秒殺的哪些功能?先來看看天貓的一個秒殺庫存系統:
你們看了是否是以爲很複雜?固然不用擔憂,咱們只是實現秒殺的一些功能:一、秒殺接口的暴露。二、執行秒殺的操做。三、相關查詢,好比說列表查詢,詳情頁查詢。咱們實現這三個功能便可。接下來進行具體的編碼工做,首先是創建數據庫以及Dao層的編碼。
-- 建立一個數據庫 CREATE DATABASE ngu_seckill; -- 使用數據庫 USE ngu_seckill; -- 省略... ... ...
完整的數據庫sql代碼,在項目的sql
文件夾裏的ngu_seckill.sql
先建立秒殺商品類com/nnngu/entity/Seckill.java
package com.nnngu.entity; import java.io.Serializable; import java.time.LocalDateTime; /** * 秒殺商品 */ public class Seckill implements Serializable { private static final long serialVersionUID = 2912164127598660137L; /* 主鍵ID*/ private long seckillId; /* 秒殺商品名字 */ private String name; /* 代碼省略,請參照項目的源代碼 */ ... ...
建立秒殺狀態類com/nnngu/entity/SuccessKilled.java
package com.nnngu.entity; import java.io.Serializable; import java.time.LocalDateTime; /** * 秒殺後的狀態 */ public class SuccessKilled implements Serializable { private static final long serialVersionUID = 1834437127882846202L; private long seckillId; /* 用戶的手機號碼*/ private long userPhone; /* 代碼省略,請參照項目的源代碼 */ ... ...
com/nnngu/dao/SeckillMapper.java
package com.nnngu.dao; import com.nnngu.entity.Seckill; import org.apache.ibatis.annotations.Param; import java.time.LocalDateTime; import java.util.List; import java.util.Map; public interface SeckillMapper { /* 代碼省略,請參照項目的源代碼 */ ... ... }
com/nnngu/dao/SuccessKilledMapper.java
package com.nnngu.dao; import com.nnngu.entity.SuccessKilled; import org.apache.ibatis.annotations.Param; public interface SuccessKilledMapper { /* 代碼省略,請參照項目的源代碼 */ ... ... }
mapper.xml
在resources
目錄下建立com.nnngu.dao
包,而後建立SeckillMapper.xml
和 SuccessKilledMapper.xml
,以下圖:
com.nnngu.dao/SeckillMapper.xml
<!-- 這裏的代碼省略 --> <!-- 請參照項目的源代碼 -->
com.nnngu.dao/SuccessKilledMapper.xml
<!-- 這裏的代碼省略 --> <!-- 請參照項目的源代碼 -->
mybatis-config.xml
配置文件的內容參照項目的源代碼
jdbc.properties
注意: jdbc.properties
裏面的屬性要根據本身的狀況進行修改。
建立applicationContext-dao.xml
以下圖:
applicationContext-dao.xml
文件的具體代碼請參照項目的源代碼。
建立測試類 com/nnngu/dao/SeckillMapperTest.java
以下圖:
該文件的具體代碼請參照項目的源代碼。
測試查詢全部商品的方法queryAll()
測試結果以下:
到此,咱們成功完成了Dao層開發及測試。下篇文章 02 Java高併發秒殺項目之Service層