大家早已熟知MVC模型,所以接下來按照這個模型來寫,見天介紹DAO層的搭建,由于這篇開始會涉及到大量的代碼,所以文末給出Github的地址,不再貼出過多的代碼。對于數據庫設計和項目介紹請閱讀以下兩篇文章
項目整體介紹
數據庫設計和項目搭建
實體類設計
這個系統主要包括兩個主要的實體類:Seckill【秒殺商品的實體類】和Seckilled【秒殺成功實體類】,
Seckill(秒殺實體類)
//秒殺商品的ID
private long seckillId;
//秒殺商品的名字
private String name;
//秒殺商品的數量
private int number;
//秒殺開始的時間
private Date startTime;
//秒殺結束的時間
private Date endTime;
//秒殺創建的時間
private Date createTime;
Seckilled(秒殺成功實體類)
//秒殺的商品的ID
private long seckillId;
//秒殺用戶的電話
private long userPhone;
//秒殺商品的狀態
private short state;
//秒殺成功的時間
private Date creteTime;
// 多對一的復合屬性
private Seckill seckill;
在秒殺成功實體類中包含一個復合屬性,在設計表的時候我們就知道,seckillId是一個外鍵,所以在展示的時候為了能將選出來的秒殺成功的實體類中包含商品的信息我們設置一個Seckill的對象用來存儲相關的信息。
DAO層接口設計
由于使用的是Mybatis,所以需要首先設計接口,主要包括兩個接口一個是用來操作商品的,一個是用來操作秒殺成功相關信息的
SeckillDao
/**
* 減庫存
*
* @param seckillId
* @param killTime
* @return 如果影響行數等于>1,表示更新的記錄行數
*/
int reduceNumber(@Param("seckillId") long seckillId, @Param("killTime") Date killTime);
/**
* 根據id查詢秒殺對象
*
* @param seckillId
* @return
*/
Seckill queryById(long seckillId);
/**
* 根據偏移量查詢秒殺商品列表
*
* @param offset
* @param limit
* @return
*/
List<Seckill> queryAll(@Param("offset") int offset, @Param("limit") int limit);
SuccessKilledDao
/**
* 插入購買明細,可過濾重復
*
* @param seckillId
* @param userPhone
* @return 插入的行數
*
*/
int insertSuccessKilled(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
/**
* 根據id查詢SuccessKilled并攜帶秒殺產品對象實體
*
* @param seckillId
* @param userPhone
* @return
*/
SuccessKilled queryByIdWithSeckill(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
到這里主要的東西都介紹完了,接下來是一些配置文件的書寫,包括mapper文件的書寫和Spring SpringMVC Mybatis的一些配置,由于都是一些大致相同的配置,所以給出源代碼的具體地址和詳細的注釋,如果有不明白的可以留言解答
Mapper文件配置
SeckillDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.icodelife.dao.SeckillDao">
<!-- 目的:為dao接口方法提供sql語句配置 -->
<update id="reduceNumber">
<!-- 具體的sql -->
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="Seckill" parameterType="long">
SELECT
seckill_id,
NAME,
number,
start_time,
end_time,
create_time
FROM
seckill
WHERE
seckill_id = #{seckillId}
</select>
<select id="queryAll" resultType="Seckill">
SELECT
seckill_id,
NAME,
number,
start_time,
end_time,
create_time
FROM
seckill
ORDER BY
create_time DESC
LIMIT #{offset},
#{limit}
</select>
</mapper>
SuccessKilledDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.icodelife.dao.SuccessKilledDao">
<insert id="insertSuccessKilled">
<!-- 主鍵沖突,報錯 -->
INSERT ignore INTO success_killed (seckill_id, user_phone, state)
VALUES (#{seckillId}, #{userPhone}, 0)
</insert>
<select id="queryByIdWithSeckill" resultType="SuccessKilled">
<!-- 如何告訴MyBatis把結果映射到SuccessKilled同
時映射seckill屬性 -->
<!-- 可以自由控制SQL -->
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.number",
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配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置全局屬性 -->
<settings>
<!-- 使用jdbc的getGeneratedKeys獲取數據庫自增主鍵值 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 使用列別名替換列名 默認:true -->
<setting name="useColumnLabel" value="true" />
<!-- 開啟駝峰命名轉換:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
數據庫配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/seckill?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=
日志配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis過程 -->
<!-- 1.配置數據庫相關參數properties的屬性:${url} -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 2.數據庫連接池 -->
<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.username}" />
<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="10000" />
<!-- 當獲取連接失敗重試次數 -->
<property name="acquireRetryAttempts" value="2" />
</bean>
<!-- 3.配置SqlSessionFactory對象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入數據庫連接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 掃描entity包 使用別名 -->
<property name="typeAliasesPackage" value="cn.icodelife.entity" />
<!-- 掃描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml" />
</bean>
<!-- 4.配置掃描Dao接口包,動態實現Dao接口,注入到soring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 給出需要掃描Dao接口包 -->
<property name="basePackage" value="cn.icodelife.dao" />
</bean>
</beans>