分享一個整合SSM框架的高併發和商品秒殺專案
一個整合SSM框架的高併發和商品秒殺專案,學習目前較流行的Java框架組合實現高併發秒殺API
專案開發流程
本專案很適合學習一些技術的基礎,這個專案的開發分為幾個流程,很基礎地教你接觸到一個相對有技術含量的專案
Java高併發秒殺API之業務分析與DAO層
Java高併發秒殺API之web層
Java高併發秒殺API之Service層
Java高併發秒殺API之高併發優化
按照上面幾個流程走下去,你要有基本的Maven認識以及Java語法的一些概念,要不然可能不太理解
其實這幾個流程也就是開發的流程,首先從DAO層開始開發,從後往前開發,開始Coding吧!
專案總結可能比較長,由於公眾號文章的字數限制今天只能先講解第一節,如果這篇文章看得人多並且點贊數較高的話明天就繼續更新,哈哈~
專案環境的搭建
作業系統 : Ubuntu 17.04
IDE :IntelliJ IDEA 2016.2.5 x64 用Eclipse也一樣的,工具時靠人用的
JDK : JDK1.8 建議使用JDK1.7以上版本,有許多語法糖用著挺舒服的
Web容器 : Tomcat 8.0
資料庫 :Mysql-5.6.17-WinX64 實驗性的專案用Mysql就足夠啦
依賴管理工具 : Maven 管理jar包真的很方便
這裡列出的環境不是必須的,你喜歡用什麼就用什麼,這裡只是給出參考,不過不同的版本可能會引起各種不同的問題就需要我們自己去發現以及排查,在這裡使用Maven的話時方便我們管理JAR包,我們不用跑去各種開源框架的官網去下載一個又一個的JAR包,配置好了Maven後新增pom檔案座標就會從中央倉庫下載JAR包,如果哪天替換版本也很方便
專案效果圖
秒殺商品列表
秒殺結束提示介面
開始秒殺提示介面
重複秒殺提示介面
秒殺成功提示介面
專案的執行
下載
Download Zip
或者 git clone
git clone https://github.com/Sunybyjava/seckill.git
匯入到IDE
這裡因為是使用IDEA
建立的專案,所以使用IDEA
直接開啟是很方便的,提前是你要配置好maven
的相關配置,以及專案JDK
版本,JDK
版本必須在1.8
以上,因為在專案中使用了Java8
的LocalDateTime
以及LocalDate
,所以低於這個版本編譯會失敗的
IDEA
直接在主介面選擇Open
,然後找到專案所在路徑,點選pom.xml
開啟就可以了Eclipse 這個專案是基於
IDEA
建立,我這裡把專案轉成了Eclipse
的專案,如果你使用Eclipse的話也可以直接匯入,只是步驟更繁瑣一點,Eclipse匯入步驟
(一)Java高併發秒殺APi之業務分析與DAO層程式碼編寫
構建專案的基本骨架
首先我們要搭建出一個符合Maven約定的目錄來,這裡大致有兩種方式,第一種:
第一種使用命令列手動構建一個maven結構的目錄,當然我基本不會這樣構建
mvn archetype:generate -DgroupId=com.suny.seckill -DartifactId=seckill -Dpackage=com.suny.seckill -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp
這裡要注意的是使用archetype:generate
進行建立,在Maven老版本中是使用archetype:create
,現在這種方法已經被棄用了,所以使用命令列建立的話注意了,稍微解釋下這段語句的意思,就是構建一個一個maven-archetype-webapp
骨架的Webapp專案,然後groupId
為com.suny.seckill
,artifactId
為seckill
,這裡是Maven相關知識,可以按照自己的情況進行修改
2.第二種直接在IDE中進行建立,這裡以IDEA為例
點選左上角
File>New>Project>Maven
然後在裡面勾選
Create from archetype
,然後再往下拉找到org.apache.cocoon:cocoon-22-archetype-webapp
,選中它,注意要先勾選那個選項,否則選擇不了,然後點選Next
繼續
+然後就填寫你的Maven的那幾個重要的座標了,自己看著填吧
+再就配置你的Maven的相關資訊,預設應該是配置好的
+之後就是點Finsh
,到此不出意外的話就應該建立成功了
構建pom檔案
專案基本的骨架我們就建立出來了,接下來我們要新增一些基本的JAR包的依賴,也就是在pom.xml
中新增各種開源元件的三座標了
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.suny.seckill</groupId>
<artifactId>seckill</artifactId>
<version>1.0-SNAPSHOT</version>
<name>seckill Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!--junit測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--配置日誌相關,日誌門面使用slf4j,日誌的具體實現由logback實現-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.1</version>
</dependency>
<!--資料庫相關依賴-->
<!--首先匯入連線Mysql資料連線-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!--匯入資料庫連線池-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--匯入mybatis依賴-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--匯入Servlet web相關的依賴-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--spring預設的json轉換-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!--匯入spring相關依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!--匯入springTest-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>seckill</finalName>
</build>
</project>
建立資料庫
在根目錄下有一個sql資料夾裡面有一個sql資料庫指令碼,如果你不想自己手寫的話就直接匯入到你的資料庫裡面去吧,不過還是建議自己手寫一遍加深印象
-- 整個專案的資料庫指令碼
-- 開始建立一個資料庫
CREATE DATABASE seckill;
-- 使用資料庫
USE seckill;
-- 建立秒殺庫存表
CREATE TABLE seckill(
`seckill_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '商品庫存ID',
`name` VARCHAR(120) NOT NULL COMMENT '商品名稱',
`number` INT NOT NULL COMMENT '庫存數量',
`start_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '秒殺開啟的時間',
`end_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '秒殺結束的時間',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '建立的時間',
PRIMARY KEY (seckill_id),
KEY idx_start_time(start_time),
KEY idx_end_time(end_time),
KEY idx_create_time(create_time)
)ENGINE =InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='秒殺庫存表';
-- 插入初始化資料
insert into
seckill(name,number,start_time,end_time)
values
('1000元秒殺iphone6',100,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
('500元秒殺iPad2',200,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
('300元秒殺小米4',300,'2016-5-22 00:00:00','2016-5-23 00:00:00'),
('200元秒殺紅米note',400,'2016-5-22 00:00:00','2016-5-23 00:00:00');
-- 秒殺成功明細表
-- 使用者登入相關資訊
create table success_killed(
`seckill_id` BIGINT NOT NULL COMMENT '秒殺商品ID',
`user_phone` BIGINT NOT NULL COMMENT '使用者手機號',
`state` TINYINT NOT NULL DEFAULT -1 COMMENT '狀態標示:-1無效 0成功 1已付款',
`create_time` TIMESTAMP NOT NULL COMMENT '建立時間',
PRIMARY KEY (seckill_id,user_phone), /*聯合主鍵*/
KEY idx_create_time(create_time)
)ENGINE =InnDB DEFAULT CHARSET =utf8 COMMENT ='秒殺成功明細表'
在建立資料庫的,如果按照我這裡的資料庫指令碼建立的話應該是沒問題的,但是我按照視訊裡面的資料庫指令碼建表的話發生了一個錯誤
這個報錯看起來比較的詭異,我仔細檢查sql
也沒有錯誤,它總提示我end_time
要有一個預設的值,可我記得我以前就不會這樣,然後視訊裡面也沒有執行錯誤,然後我感覺可能時MySQL
版本的差異,我檢視了下我資料庫版本,在登入Mysql
控制檯後輸入指令,在控制檯的我暫時知道的有兩種方式:
select version();
select @@version;
我的輸出結果如下:
進控制檯就已經可以看到版本了,我的Mysql是5.7
的,以前我用的時5.6
的,然後去Google
上搜尋了下,找到了幾個答案,參考連結:
https://stackoverflow.com/questions/9192027/invalid-default-value-for-create-date-timestamp-field
mysql官方的解釋:https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_date
https://stackoverflow.com/questions/34570611/mysql-community-5-7-invalid-default-value-datetime-field-type
總結出來一句話就是:
mysql 5.7中,預設使用的是嚴格模式,這裡的日期必須要有時間,所以一定要給出預設值,要麼就修改資料庫設定
然後網友評論裡總結出來的幾種解決辦法,未經測試!:
下次有問題一定要先看一下評論!!!create不了的同學,可以這樣寫:
`start_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '秒殺開始時間',
`end_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '秒殺結束時間',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
關於timestamp的問題,需要先執行 set explicit_defaults_for_timestamp = 1,否則會報invalid default value錯誤
還需要注意的是SQL版本的問題會導致視訊中seckill表建立會出錯。只要將create_time放在start_time和end_time之前是方便的解決方法。
對比下我修改過後的跟視訊裡面的sql
片段:
我們可以看到在這三個欄位有一個小差別,那就是給start_time
,end_time
,create_time
三個欄位都新增一個預設值,然後執行資料庫語句就沒問題了
這裡我們需要修改下web.xml
中的servlet版本為3.0
開啟WEB-INF
下的web.xml
,修改為以下程式碼:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<!--用maven建立的web-app需要修改servlet的版本為3.0-->
修改的原因有以下幾點:
高版本的Servlet支援更多的特性,更方便我們的Coding,特別是支援註解這一特性
在
Servlet2.3
中新加入了Listener
介面的實現,,我們可以使用Listener
引入Spring
的ContextLoaderListener
舉個例子:
在
Servlet2.3
以前我們這樣配置ContextLoaderListener
:
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
在
Servlet2.3
以後可以使用Listener
配置,也就是我們專案中使用的方法
<listener>
<listener-class>org.springframework.context.ContextLoaderListener</listener-class>
</listener>
兩種方法的效果都是一樣的,主要不要同時使用,否則會報錯的
建立實體類
首先建立
SuccessKilled
秒殺狀態表
package com.suny.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;
/* 秒殺的狀態*/
private short state;
/* 建立時間*/
private LocalDateTime createTime;
/* 多對一,因為一件商品在庫存中肯定有許多,對應的購買資訊也有很多*/
private Seckill seckill;
public SuccessKilled() {
}
public SuccessKilled(long seckillId, long userPhone, short state, LocalDateTime createTime, Seckill seckill) {
this.seckillId = seckillId;
this.userPhone = userPhone;
this.state = state;
this.createTime = createTime;
this.seckill = seckill;
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public long getUserPhone() {
return userPhone;
}
public void setUserPhone(long userPhone) {
this.userPhone = userPhone;
}
public short getState() {
return state;
}
public void setState(short state) {
this.state = state;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public Seckill getSeckill() {
return seckill;
}
public void setSeckill(Seckill seckill) {
this.seckill = seckill;
}
@Override
public String toString() {
return "SuccessKilled{" +
"主鍵ID=" + seckillId +
", 手機號碼=" + userPhone +
", 秒殺狀態=" + state +
", 建立時間=" + createTime +
", 秒殺的商品=" + seckill +
'}';
}
}
再建立
Seckill
秒殺商品資訊
package com.suny.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;
/* 秒殺的商品編號 */
private int number;
/* 開始秒殺的時間 */
private LocalDateTime startTime;
/* 結束秒殺的時間 */
private LocalDateTime endTime;
/* 建立的時間 */
private LocalDateTime createTIme;
public Seckill() {
}
public Seckill(long seckillId, String name, int number, LocalDateTime startTime, LocalDateTime endTime, LocalDateTime createTIme) {
this.seckillId = seckillId;
this.name = name;
this.number = number;
this.startTime = startTime;
this.endTime = endTime;
this.createTIme = createTIme;
}
public long getSeckillId() {
return seckillId;
}
public void setSeckillId(long seckillId) {
this.seckillId = seckillId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public LocalDateTime getStartTime() {
return startTime;
}
public void setStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
public LocalDateTime getEndTime() {
return endTime;
}
public void setEndTime(LocalDateTime endTime) {
this.endTime = endTime;
}
public LocalDateTime getCreateTIme() {
return createTIme;
}
public void setCreateTIme(LocalDateTime createTIme) {
this.createTIme = createTIme;
}
@Override
public String toString() {
return "com.suny.entity.Seckill{" +
"主鍵ID=" + seckillId +
", 秒殺商品='" + name + '\'' +
", 編號=" + number +
", 開始秒殺時間=" + startTime +
", 結束秒殺時間=" + endTime +
", 建立時間=" + createTIme +
'}';
}
}
對實體類建立對應的mapper
介面,也就是dao
介面類
首先建立
SeckillMapper
,在我這裡位於com.suny.dao
包下
package com.suny.dao;
import com.suny.entity.Seckill;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
public interface SeckillMapper {
/**
* 根據傳過來的<code>seckillId</code>去減少商品的庫存.
*
* @param seckillId 秒殺商品ID
* @param killTime 秒殺的精確時間
* @return 如果秒殺成功就返回1,否則就返回0
*/
int reduceNumber(@Param("seckillId") long seckillId, @Param("killTime") LocalDateTime killTime);
/**
* 根據傳過來的<code>seckillId</code>去查詢秒殺商品的詳情.
*
* @param seckillId 秒殺商品ID
* @return 對應商品ID的的資料
*/
Seckill queryById(@Param("seckillId") long seckillId);
/**
* 根據一個偏移量去查詢秒殺的商品列表.
*
* @param offset 偏移量
* @param limit 限制查詢的資料個數
* @return 符合偏移量查出來的資料個數
*/
List<Seckill> queryAll(@Param("offset") int offset, @Param("limit") int limit);
}
再建立
SuccessKilledMapper
package com.suny.dao;
import com.suny.entity.SuccessKilled;
import org.apache.ibatis.annotations.Param;
public interface SuccessKilledMapper {
/**
* 插入一條詳細的購買資訊.
*
* @param seckillId 秒殺商品的ID
* @param userPhone 購買使用者的手機號碼
* @return 成功插入就返回1, 否則就返回0
*/
int insertSuccessKilled(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
/**
* 根據秒殺商品的ID查詢<code>SuccessKilled</code>的明細資訊.
*
* @param seckillId 秒殺商品的ID
* @param userPhone 購買使用者的手機號碼
* @return 秒殺商品的明細資訊
*/
SuccessKilled queryByIdWithSeckill(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
}
接下來書寫xml
配置檔案
建立對應的mapper.xml
首先在src/main/resources
建立com.suny.dao
這個包,也就是對應mapper
介面檔案包一樣的包名,這樣符合Maven的約定,就是資源放置在Resource
包下,Java
包下則是放置java
類檔案,編譯後最後還是會在同一個目錄下
首先建立
SeckillMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.suny.dao.SeckillMapper">
<!--這裡的<=需要使用進行忽略,所以是要進行忽略,使用CDATA 區段中的文字會被解析器忽略 -->
<update id="reduceNumber">
UPDATE seckill
SET number = number - 1
WHERE seckill_id = #{seckillId}
AND start_time
<![CDATA[
<=
]]>
#{killTime}
AND end_time >= #{killTime}
AND number > 0
</update>
<select id="queryById" resultType="com.suny.entity.Seckill">
SELECT
*
FROM seckill AS s
WHERE s.seckill_id = #{seckillId}
</select>
<select id="queryAll" resultType="com.suny.entity.Seckill">
SELECT
*
FROM seckill AS s
ORDER BY create_time DESC
LIMIT #{offset}, #{limit}
</select>
</mapper>
建立
SuccessKilledMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.suny.dao.SuccessKilledMapper">
<!--新增主鍵衝突時忽略錯誤返回0-->
<insert id="insertSuccessKilled">
INSERT IGNORE INTO success_killed (seckill_id, user_phone, state)
VALUES (#{seckillId}, #{userPhone}, 0)
</insert>
<!--根據seckillId查詢SuccessKilled物件,並攜帶Seckill物件,告訴mybatis把對映結果對映到SuccessKill屬性同時對映到Seckill屬性-->
<select id="queryByIdWithSeckill" resultType="com.suny.entity.SuccessKilled">
SELECT
sk.seckill_id,
sk.user_phone,
sk.create_time,
sk.state,
s.seckill_id "seckill.seckill_id",
s.name "seckill.name",
s.number "seckill",
s.start_time "seckill.start_time",
s.end_time "seckill.end_time",
s.create_time "seckill.create_time"
FROM success_killed sk
INNER JOIN seckill s ON sk.seckill_id = s.seckill_id
WHERE sk.seckill_id = #{seckillId}
AND sk.user_phone= #{userPhone}
</select>
</mapper>
建立
Mybatis
的配置檔案mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>
<!--首先配置全域性屬性-->
<settings>
<!--開啟自動填充主鍵功能,原理時通過jdbc的一個方法getGeneratekeys獲取自增主鍵值-->
<setting name="useGeneratedKeys" value="true"/>
<!--使用別名替換列名,預設就是開啟的-->
<setting name="useColumnLabel" value="true"/>
<!--開啟駝峰命名的轉換-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
然後建立連線資料庫的配置檔案
jdbc.properties
,這裡的屬性要根據自己的需要去進行修改,切勿直接複製使用
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8
建立
Spring
的dao
的配置檔案,在resources
包下建立applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置資料庫連線池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--配置基本的資料庫連線-->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<!--c3p0私有屬性-->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!--關閉連線後不自動commit-->
<property name="autoCommitOnClose" value="false"/>
<!--獲取連線超時時間-->
<property name="checkoutTimeout" value="1000"/>
<!--當獲取連線失敗時的重試次數-->
</bean>
<!--配置sqlSessionFactory物件-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入資料庫連線池-->
<property name="dataSource" ref="dataSource"/>
<!--配置mybatis全域性配置檔案-->
<property name="configLocation" value="mybatis-config.xml"/>
<!--配置entity包,也就是實體類包,自動掃描,用於別名配置-->
<property name="typeAliasesPackage" value="com.suny.entity"/>
<!--配置需要掃描的mapper.xml檔案-->
<property name="mapperLocations" value="classpath*:com/suny/dao/*.xml"/>
</bean>
<!--配置mapper介面包,動態實現mapper介面,注入到Spring容器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory,請注意不要使用sqlSessionFactoryBean,否則會出現注入異常-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--給出要掃描的mapper介面-->
<property name="basePackage" value="com.suny.dao"/>
</bean>
</beans>
基礎的部分我們搭建完成了,然後要開始測試了 在
IDEA
裡面有一個快速建立測試的快捷鍵Ctrl+Shift+T
,在某個要測試的類裡面按下這個快捷鍵就會出現Create new Test
,然後選擇你要測試的方法跟測試的工具就可以了,這裡我們使用Junit作為測試建立
SeckillMapperTest
檔案,程式碼如下
package com.suny.dao;
import com.suny.entity.Seckill;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/applicationContext-dao.xml"})
public class SeckillMapperTest {
@Resource
private SeckillMapper seckillMapper;
@Test
public void reduceNumber() throws Exception {
long seckillId=1000;
LocalDateTime localDateTime=LocalDateTime.now();
int i = seckillMapper.reduceNumber(seckillId, localDateTime);
System.out.println(i);
}
@Test
public void queryById() throws Exception {
long seckillId = 1000;
Seckill seckill = seckillMapper.queryById(seckillId);
System.out.println(seckill.toString());
}
@Test
public void queryAll() throws Exception {
List<Seckill> seckills = seckillMapper.queryAll(0, 100);
for (Seckill seckill : seckills) {
System.out.println(seckill.toString());
}
}
}
測試中可能會出現Mybatis
引數繫結失敗的錯誤,在mapper
介面中的方法裡面新增@Param
的註解,顯示的告訴mybatis引數的名稱是什麼,例如
List<Seckill> queryAll(@Param("offset") int offset, @Param("limit") int limit);
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、轉發。
(未完待續)
Java團長
專注於Java乾貨分享
掃描上方二維碼獲取更多Java乾貨
相關文章
- SSM框架實現高併發秒殺API學習筆記SSM框架API筆記
- 高併發秒殺專案隨手筆記筆記
- 高併發下秒殺商品,必須知道的9個細節
- PHP高併發商品秒殺問題的解決方案PHP
- 如何設計一個高可用、高併發秒殺系統
- PHP高併發 商品秒殺 問題的 2大種(MySQL or Redis) 解決方案PHPMySqlRedis
- 高併發秒殺系統架構詳解,不是所有的秒殺都是秒殺!架構
- (四)Java高併發秒殺API之高併發優化JavaAPI優化
- RocketMQ實戰--高併發秒殺場景MQ
- 【高併發】秒殺系統架構解密,不是所有的秒殺都是秒殺(升級版)!!架構解密
- 【SSM框架整合】專案xml檔案、properties等檔案的配置SSM框架XML
- SSM框架整合開發SSM框架
- SSM框架整合(配置檔案)SSM框架
- (二)Java高併發秒殺API之Service層JavaAPI
- Redis 實現高併發下的搶購 / 秒殺功能Redis
- SSM框架的整合SSM框架
- Java高併發秒殺系統【觀後總結】Java
- 搭建一個SSM專案SSM
- SSM專案整合——後端SSM後端
- SSM框架整合SSM框架
- 整合SSM框架SSM框架
- 【高併發】Redis如何助力高併發秒殺系統,看完這篇我徹底懂了!!Redis
- 使用Redis構建高併發高可靠的秒殺拍賣系統 - LuisRedisUI
- 高併發業務場景下的秒殺解決方案 (初探)
- 高併發!一個仿 12306 鐵路購票專案!
- (三)Java高併發秒殺系統API之Web層開發JavaAPIWeb
- 設計一個支援高併發的分散式鎖,商品維度分散式
- 短影片直播系統,實現高併發秒殺的多種方式
- IDEA使用maven搭建SSM框架整合專案(超級詳細,值得一看)IdeaMavenSSM框架
- SpringBoot專案建立與第一個SSM專案示例Spring BootSSM
- ssm框架整合筆記SSM框架筆記
- SSM框架整合流程SSM框架
- SpringBoot實現Java高併發秒殺系統之Web層開發(三)Spring BootJavaWeb
- 分享一門go最強實戰課程《全流程開發 GO實戰電商網站高併發秒殺系統》——推薦分享Go網站
- 配置一個簡單的傳統SSM專案SSM
- Day73 SSM專案 搭建框架SSM框架
- Redis+Lua解決高併發場景搶購秒殺問題Redis
- 6步帶你用Spring Boot開發出商城高併發秒殺系統Spring Boot