【SSM 项目:Java 高并发秒杀 API (一)】1 业务分析与 DAO 层

【SSM 项目:Java 高并发秒杀 API (一)】1 业务分析与 DAO 层,第1张

【SSM 项目:Java 高并发秒杀 API (一)】1 业务分析与 DAO 层

文章目录
  • 1. 项目概述
    • 1.1 SSM 框架优点
    • 1.2 相关技术介绍
    • 1.3 秒杀业务分析
      • 1.3.1 秒杀系统业务流程
      • 1.3.2 秒杀业务的核心:对库存的处理
      • 1.3.3 为什么需要事务
      • 1.3.4 关于数据落地
    • 1.4 MySQL 实现秒杀难点分析
    • 1.5 实现哪些秒杀功能
  • 2. 创建项目和依赖
    • 2.1 创建前的说明
    • 2.2 开始创建项目
    • 2.3 导入依赖
  • 3. 数据库设计编码
  • 4. DAO 层实体和接口编码
    • 4.1 编写 entity 实体类
      • 4.1.1 Seckill 实体类
      • 4.1.2 SuccessKilled 类
    • 4.2 设计 DAO 接口
      • 4.2.1 SeckillDao 接口
      • 4.2.2 SuccessKilledDao 接口

1. 项目概述



1.1 SSM 框架优点
  • 框架易于使用和轻量级
  • 低代码侵入性
  • 成熟的社区和用户群
1.2 相关技术介绍

1.MySQL

  • 表设计
  • SQL 技巧
  • 事务和行级锁

2.MyBatis

  • DAO 层设计与开发
  • MyBatis 合理使用
  • MyBatis 与 Spring 整合

3.Spring

  • Spring IOC 整合 Service
  • 声明式事务运用

4.SpringMVC

  • Restful 接口设计和使用
  • 框架运作流程
  • Controller 开发技巧

5.前端

  • 交互设计
  • Bootstrap
  • jQuery

6.高并发

  • 高并发点和高并发分析
  • 优化思路并实现
1.3 秒杀业务分析 1.3.1 秒杀系统业务流程

1.3.2 秒杀业务的核心:对库存的处理


1.3.3 为什么需要事务

1.3.4 关于数据落地

MySQL VS NoSQL

NoSQL:对事务支持不是很好,追求的是性能、高可用、分布式
MySQL:内置的事务机制依然是目前最有效、最可靠的数据落地方案 -> 可以更可靠的记录减库存、记录购买行为

1.4 MySQL 实现秒杀难点分析

难点问题: 竞争 -> 事务 +行级锁

事务工作机制:

  • Start Transaction
  • Update 库存数量 -> 竞争出现在此处
  • Insert 购买明细
  • Commit

行级锁 -> 伴随着竞争

如何高效的处理竞争:高并发

1.5 实现哪些秒杀功能
  • 秒杀接口暴露
  • 执行秒杀
  • 相关查询: 列表查询、详情页查询

代码开发阶段

  • DAO 设计编码 :数据库表设计、DAO 接口、MyBatis 如何实现 DAO
  • Service 设计编码:
    Service 接口设计及编码实现、通过 Spring 管理 Service、通过 Spring 声明式事务标注 Service 方法是一个事务 *** 作简化事务控制
  • Web 设计编码:Restful 接口、 前端交互
2. 创建项目和依赖 2.1 创建前的说明
  • 从零开始创建

  • 从官网获取相关配置
    1.文档更全面权威
    2.避免过时或错误

  • 使用 Maven 创建项目

2.2 开始创建项目
  1. 新建 Maven 项目

    Maven 安装及其在 IDEA 中的配置和使用 (保姆级教程)

  2. 新建 Web 项目

    Java 学习【框架篇(三)】SpringMVC(一)回顾 MVC 架构 & Servlet

结果如下:

2.3 导入依赖


    4.0.0

    org.seckill
    seckill
    1.0-SNAPSHOT

    
        
            
            junit
            junit
            4.11
            test
        

        

        
        
            org.slf4j
            slf4j-api
            1.7.12
        
        
            ch.qos.logback
            logback-core
            1.1.1
        
        
        
            ch.qos.logback
            logback-classic
            1.1.1
        

        
        
        
            mysql
            mysql-connector-java
            5.1.35
            runtime
        
        
        
            com.mchange
            c3p0
            0.9.5.2
        

        
        
        
            org.mybatis
            mybatis
            3.3.0
        
        
        
            org.mybatis
            mybatis-spring
            1.2.3
        

        
        
        
            taglibs
            standard
            1.1.2
        
        
        
            jstl
            jstl
            1.2
        
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.5.4
        
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
        

        
        
        
            org.springframework
            spring-core
            4.1.7.RELEASE
        
        
            org.springframework
            spring-beans
            4.1.7.RELEASE
        
        
            org.springframework
            spring-context
            4.1.7.RELEASE
        
        
        
            org.springframework
            spring-jdbc
            4.1.7.RELEASE
        
        
        
            org.springframework
            spring-tx
            4.1.7.RELEASE
        
        
        
            org.springframework
            spring-web
            4.1.7.RELEASE
        
        
            org.springframework
            spring-webmvc
            4.1.7.RELEASE
        
        
        
            org.springframework
            spring-test
            4.1.7.RELEASE
        

    

3. 数据库设计编码

Java 学习【框架篇(二)】MyBatis(一)第一个 MyBatis 查询程序

  1. main 下新建 schema.sql

schema.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` datetime NOT NULL COMMENT '秒杀开始时间',
`end_time` datetime NOT NULL COMMENT '秒杀结束时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 设计索引
-- idx 为 index 简称
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, '2015-11-01 00:00:00', '2015-11-02 00:00:00'),
    ('500 元秒杀 ipad2',  200, '2015-11-01 00:00:00', '2015-11-02 00:00:00'),
    ('300 元秒杀小米 4',  300, '2015-11-01 00:00:00', '2015-11-02 00:00:00'),
    ('200 元秒杀红米 note',  400, '2015-11-01 00:00:00', '2015-11-02 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: 已付款 2: 已发货',
`create_time` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`seckill_id`, `user_phone`),  -- 联合主键
key idx_create_time(create_time)
)ENGINE = InnoDB DEFAULT CHARSET = utf8 COMMENT '秒杀成功明细表';

修改数据库字段属性:

ALTER TABLE `success_killed` MODIFY `create_time` datetime;

显示表是怎么创建的:

show CREATE TABLE `success_killed`;
CREATE TABLE `success_killed` (
  `seckill_id` bigint(20) NOT NULL COMMENT '秒杀商品 id',
  `user_phone` bigint(20) NOT NULL COMMENT '用户手机号',
  `state` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '状态标识: -1: 无效 0: 成功 1: 已付款 2: 已发货',
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`seckill_id`,`user_phone`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表'

结果如下:

4. DAO 层实体和接口编码

tabel 和 entity 的对应关系

  • 表对应 Java 中的实体类
  • 列对应实体中的属性

创建实体包 & DAO 层的包
org.seckill.entity
org.seckill.dao

4.1 编写 entity 实体类 4.1.1 Seckill 实体类
package org.seckill.entity;

import java.util.Date;

public class Seckill {
    private long seckillId;
    private String name;
    private int number;
    private Date startTime;
    private Date endTime;
    private Date createTime;

    // Alt + insert
    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 Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Seckill{" +
                "seckillId=" + seckillId +
                ", name='" + name + ''' +
                ", number=" + number +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                ", createTime=" + createTime +
                '}';
    }
}
4.1.2 SuccessKilled 类
package org.seckill.entity;

import java.util.Date;

public class SuccessKilled {
    private long skillId;
    private long userPhone;
    private short state;
    private Date createTime;

    // 变通
    // 多对一(复合属性): 一个 Seckill 实体对应多个秒杀成功的记录
    private Seckill seckill;

    public long getSkillId() {
        return skillId;
    }

    public void setSkillId(long skillId) {
        this.skillId = skillId;
    }

    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 Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Seckill getSeckill() {
        return seckill;
    }

    public void setSeckill(Seckill seckill) {
        this.seckill = seckill;
    }

    @Override
    public String toString() {
        return "SuccessKilled{" +
                "skillId=" + skillId +
                ", userPhone=" + userPhone +
                ", state=" + state +
                ", createTime=" + createTime +
                '}';
    }
}
4.2 设计 DAO 接口 4.2.1 SeckillDao 接口

命名规范: 对应的实体 + Dao -> 如:SeckillDao

package org.seckill.dao;

import org.seckill.entity.Seckill;

import java.util.Date;
import java.util.List;

public interface SeckillDao {

    // 减库存 (killTime 执行减库存的时间 对应数据库中的 creatTime)
    // 如果影响行数 >1, 表示更新的记录行数
    int reduceNumber(long seckillId, Date killTime);

    // 查询需求(根据 id 查询秒杀对象)
    Seckill queryById(long seckillId);

    // 根据偏移量查询秒杀商品列表
    // offset:偏移量, limit:在偏移量之后取多少条记录
    List queryAll(int offset, int limit);
}

4.2.2 SuccessKilledDao 接口
package org.seckill.dao;

import org.seckill.entity.SuccessKilled;

public interface SuccessKilledDao {

    // 插入购买明细,可过滤重复(联合唯一主键)
    // 插入的行数
    int insertSuccessKilled(long seckillId, long userPhone);

    // 根据 id 查询 SuccessKilled 并携带秒杀产品对象实体
    SuccessKilled queryByIdWithSeckill(long seckillId);
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5676753.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存