本篇文章是“ Java 秒杀系统实战系列文章”的第三篇,本文将主要介绍秒杀系统的整体业务流程,并根据相应的业务流程进行 数据库设计 ,最终采用 Mybatis 逆向工程生成相应的实体类Entity、操作Sql的接口Mapper以及写动态Sql的配置文件Mapper.xml。
对于该秒杀系统的整体业务流程,相信机灵的小伙伴在看完第二篇文章《 》时,就已经知道个大概了!
因为在提供的源码数据库下载的链接中,Debug已经跟各位小伙伴介绍了该秒杀系统整体的业务流程,而且还以视频形式给各位小伙伴进行了展示!该源码数据库的下载链接如下:
在本文中Debug将继续花一点篇幅介绍介绍!
一图以概之,如下图所示为该秒杀系统整体的业务流程:
从该业务流程图中,可以看出,后端接口在接收前端的秒杀请求时,其核心处理逻辑为:
(1)首先判断当前用户是否已经抢购过该商品了,如果否,则代表用户没有抢购过该商品,可以进入下一步的处理逻辑;
(2)判断该商品可抢的剩余数量,即库存是否充足(即是否大于0),如果是,则进入下一步的处理逻辑;
(3)扣减库存,并更新数据库的中对应抢购记录的库存(一般是减一操作),判断更新库存的数据库操作是否成功了,如果是,则创建用户秒杀成功的订单,并异步发送短信或者邮件通知信息通知用户;
(4)以上的操作逻辑如果有任何一步是不满足条件的,则直接结束整个秒杀的流程,即秒杀失败。
如下图所示为后端处理“秒杀请求”时的核心处理逻辑:
综合这两个业务流程,下面进入“秒杀系统”的数据库设计环节,其中,主要包含以下几个表:商品信息表item、待秒杀信息表item_kill、秒杀成功记录表item_kill_success以及用户信息表user;当然,在实际的大型网站中,其所包含的数据库表远远不止于此!本系统暂且浓缩出其中核心的几张表!
如下图所示为该“秒杀系统”的数据库设计模型:
紧接着,是采用Mybatis的逆向工程生成这几个数据库表对应的实体类Entity、操作Sql的接口Mapper以及写动态Sql的配置文件Mapper.xml。如下图所示:
下面,贴出其中一个实体类以及相对应的Mapper接口和Mapper.xml代码,其他的,各位小伙伴可以点击链接:
前往下载查看!首先是实体类ItemKill的源代码:
import com .fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.util.Date; @Data public class ItemKill { private Integer id; private Integer itemId; private Integer total ; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone ="GMT+8") private Date startTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone ="GMT+8") private Date endTime; private Byte isActive; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone ="GMT+8") private Date createTime; private String itemName; //采用服务器时间控制是否可以进行抢购 private Integer canKill; }
然后是ItemKillMapper接口的源代码:
import com.debug.kill.model.entity.ItemKill; import org.apache.ibatis.annotations.Param; import java.util.List; public interface ItemKillMapper { List<ItemKill> selectAll(); ItemKill selectById(@Param("id") Integer id); int updateKillItem(@Param("killId") Integer killId); ItemKill selectByIdV2(@Param("id") Integer id); int updateKillItemV2(@Param("killId") Integer killId); }
最后是ItemKillMapper.xml配置文件的源代码:
<mappernamespace="com.debug.kill.model.mapper.ItemKillMapper" > <resultMap id="BaseResultMap"type="com.debug.kill.model.entity.ItemKill" > <idcolumn="id" property="id" jdbcType="INTEGER"/> <result column="item_id" property="itemId"jdbcType="INTEGER" /> <result column="total" property="total"jdbcType="INTEGER" /> <result column="start_time" property="startTime"jdbcType="TIMESTAMP" /> <result column="end_time" property="endTime"jdbcType="TIMESTAMP" /> <result column="is_active" property="isActive"jdbcType="TINYINT" /> <result column="create_time"property="createTime" jdbcType="TIMESTAMP" /> </resultMap> <sqlid="Base_Column_List" > id, item_id, total, start_time, end_time,is_active, create_time </sql> <!--查询待秒杀的活动商品列表--> <selectid="selectAll"resultType="com.debug.kill.model.entity.ItemKill"> SELECT a.*, b.nameAS itemName, ( CASE WHEN (now() BETWEEN a.start_time AND a.end_time AND a.total > 0) THEN 1 ELSE 0 END ) AS canKill FROM item_kill AS a LEFT JOIN item AS b ON b.id = a.item_id WHERE a.is_active = 1 </select> <!--获取秒杀详情--> <selectid="selectById" resultType="com.debug.kill.model.entity.ItemKill"> SELECT a.*, b.nameAS itemName, ( CASE WHEN (now() BETWEEN a.start_time AND a.end_time AND a.total > 0) THEN 1 ELSE 0 END ) AS canKill FROM item_kill AS a LEFT JOIN item AS b ON b.id = a.item_id WHERE a.is_active = 1 AND a.id= #{id} </select> <!--抢购商品,剩余数量减一--> <updateid="updateKillItem"> UPDATE item_kill SET total= total - 1 WHERE id =#{killId} </update> <!--获取秒杀详情V2--> <selectid="selectByIdV2"resultType="com.debug.kill.model.entity.ItemKill"> SELECT a.*, b.name AS itemName, (CASE WHEN (now() BETWEEN a.start_time AND a.end_time) THEN 1 ELSE 0 END) AS canKill FROM item_kill AS a LEFT JOIN item AS b ON b.id = a.item_id WHERE a.is_active = 1 AND a.id =#{id} AND a.total>0 </select> <!--抢购商品,剩余数量减一--> <updateid="updateKillItemV2"> UPDATE item_kill SET total= total - 1 WHERE id= #{killId} AND total>0 </update> </mapper>
值得注意的是,上面实体类ItemKill、ItemKillMapper接口的相应方法及其对应的动态Sql的含义,各位小伙伴可以暂且忽略,在后面介绍到相应的业务实战时将会再次进行重点介绍。
至此,关于“秒杀系统”整体的业务流程、后端接口的核心处理逻辑以及Mybatis逆向工程的应用等就介绍到这里了。下一节将进入实际的代码实战环节!
推荐阅读: