Java高并发秒杀Api-业务分析与DAO层构建2

章节目录

  • DAO 设计编码
    • 数据库设计与编码
    • DAO层实体和接口编码
    • 基于mybatis实现DAO理论
    • 基于mybatis实现DAO接口-1
    • mybatis整合Spring
    • DAO层编码解析

Dao 设计编码

1.pom.xml 引入项目依赖的包


    4.0.0
    org.seckill
    seckill
    war
    1.0
    seckill Maven Webapp
    http://maven.apache.org
    
        
            junit
            junit
            
            4.11
            test
        
        
        
        
        
        
            org.slf4j
            slf4j-api
            1.7.12
        

        
            ch.qos.logback
            logback-core
            1.1.2
        
        
        
            ch.qos.logback
            logback-classic
            1.1.2
        

        
        
            mysql
            mysql-connector-java
            5.1.35
            runtime
        
        
        
            c3p0
            c3p0
            0.9.1.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
        


    
    
        seckill
    

2.数据库设计与编码
数据库脚本如下所示:

--数据库初始化脚本

--创建数据库
CREATE DATABASE seckill;

--使用数据库
use seckill;

--创建秒杀库存表
CREATE TABLE seckill(
   `seckill_id` bigint not null AUTO_INCREMENT COMMENT '商品库存id',
   `name` VARCHAR (120) not null COMMENT '商品名称',
   `stock` int not null COMMENT '库存数量',
   `start_time` TIMESTAMP NOT  NULL COMMENT '秒杀开始时间',
   `end_time` TIMESTAMP  NOT NULL 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,stock,start_time,end_time)
VALUES ('1000元秒杀iphone x','100','2018-05-04 00:00:00','2018-05-05 00:00:00'),
       ('500元秒杀ipad x','200','2018-05-04 00:00:00','2018-05-05 00:00:00'),
       ('300元秒杀小米4','300','2018-05-04 00:00:00','2018-05-05 00:00:00'),
       ('200元秒杀小米note','400','2018-05-04 00:00:00','2018-05-05 00:00:00');

--秒杀成功明细表
CREATE TABLE success_killed(
  `seckill_id` bigint NOT NULL COMMENT '秒杀商品id',
  `user_phone` VARCHAR(11) 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=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表';

--连接数据库的控制台
mysql -u root -p

3.DAO层实体与接口编码

Java高并发秒杀Api-业务分析与DAO层构建2_第1张图片
数据库与实体类映射

3.1MyBatis 实现DAO接口的方式

  • Mapper自动实现DAO接口
    sql直接编写,注解sql(sql更改,原代码需要重新编译),xml方式,单独更新sql,源文件不需要重新编译。
  • API 编程方式自动实现DAO 接口

3.2 基于mybatis实现DAO接口-1

  • 全局mybatis-conf.xml




    
        
        
        
        
        
        
        
        
        
        
    

  • SecKillDao.xml编写



    
    
        
        UPDATE
        seckill
        SET
        stock = stock - 1
        WHERE
        seckill_id = #{secKillId}
        AND
        start_time  #{killTime}
        AND
        end_time >= #{killTime}
        and stock > 0
    

    

    


  • SuccessKilledDao.xml 编写



   
      
      INSERT ignore INTO
      success_killed(seckill_id,user_phone)
      VALUES
      (#{secKillId},#{userPhone})
   

    

  • entity实体层实现-SecKill、SuccessKilled
package org.seckill.domain;

import java.util.Date;

/**
 * 秒杀-库存表 entity
 */
public class SecKill {
    private long seckillId; //秒杀-商品id
    private String name;    //秒杀-商品名字
    private int stock;      //秒杀-商品库存
    private Date startTime; //秒杀-开始时间
    private Date endTime;   //秒杀-结束时间
    private Date 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 getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }

    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 + '\'' +
                ", stock=" + stock +
                ", startTime=" + startTime +
                ", endTime=" + endTime +
                ", createTime=" + createTime +
                '}';
    }
}

package org.seckill.domain;

import java.util.Date;

/**
 * 成功秒杀明细表-SuccessKilled
 */
public class SuccessKilled {
    private long secKillId;    //秒杀-成功的商品id
    private String userPhone;  //秒杀-成功的用户手机号
    private short state;       //秒杀-明细状态
    private Date createTime;   //秒杀-秒杀成功的时间

    //one(被秒杀商品)-to-many(秒杀记录)
    private SecKill secKill;

    public long getSecKillId() {
        return secKillId;
    }

    public void setSecKillId(long secKillId) {
        this.secKillId = secKillId;
    }

    public String getUserPhone() {
        return userPhone;
    }

    public void setUserPhone(String 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{" +
                "secKillId=" + secKillId +
                ", userPhone='" + userPhone + '\'' +
                ", state=" + state +
                ", createTime=" + createTime +
                '}';
    }
}
  • DAO层接口功能声明-SecKillDao、SuccessKilledDao
package org.seckill.dao;

import org.seckill.domain.SecKill;

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

/**
 * 常用的操作
 */

public interface SecKillDao {
    /**
     * 功能:减库存
     * @param secKillId
     * @param killTime create_time?
     * @return 如果影响行数>1,表示更新的记录行数
     */
    int reduceStock(long secKillId,Date killTime);

    /**
     * 根据秒杀商品id查询秒杀商品详情
     * @param secKillId
     * @return
     */
    SecKill queryById(long secKillId);

    /**
     * 根据偏移量查询秒杀商品列表,
     * @param offset
     * @param limit
     * @return
     */
    List queryAll(int offset,int limit);

}

package org.seckill.dao;

import org.seckill.domain.SuccessKilled;

public interface SuccessKilledDao {
    /**
     * 功能:新增用户秒杀明细
     * @param secKillId
     * @param userPhone
     * @return 插入的行数,禁止插入表示插入失败 则返回0
     */
    int insertSuccessKilled(long secKillId,long userPhone);

    /**
     * 功能:根据明细id查询具体的秒杀明细并携带秒杀商品对象
     * @param secKillId
     * @return
     */
    SuccessKilled queryByIdWithSecKill(long secKillId);
}

MyBatis整合Spring

整合的目标:

  • 更少的编码
  • 更少的配置
  • 足够的灵活性
    1.mybatis优点
更少的编码、只写接口、不写实现

2.DAO层接口声明能显示说明很多事情

Java高并发秒杀Api-业务分析与DAO层构建2_第2张图片
轻量级显式接口声明

更少的配置-别名

Java高并发秒杀Api-业务分析与DAO层构建2_第3张图片
image.png

使用spring 提供的package-scan 扫描实体包下的所有实体类。可以简写resultType

更少的配置-配置扫描

  • 单独使用mybatis的场景下,配置文件扫描方式

....

  • 使用spring 整合 mybatis 自动扫描配置文件,采用通配符的方式。

  • 自动实现DAO接口,DAO接口的实现类是自动注入至Spring 容器

足够的灵活性

Java高并发秒杀Api-业务分析与DAO层构建2_第4张图片
image.png

5.DAO层接口设计与SQL编写的反思

DAO - data access object 数据访问层的简称
这一层我们主要做的是核心数据操作的接口声明,以及SQL编写,并没有涉及到Service 业务逻辑层代码的编写。这样做的好处是什么呢?
主要有以下三点

  • 代码分层,DAO层只关注于核心数据操作的接口声明&SQL编写
  • 代码和SQL的分离,方便代码review
  • 业务逻辑层主要做事务控制、事务中完成DAO层的代码组合与拼接。每一层都可以做单元测试。

接下来详解mybatis 与 spring 整合编码的过程

你可能感兴趣的:(Java高并发秒杀Api-业务分析与DAO层构建2)