基于SpringMVC+Spring+MyBatis实现秒杀系统【数据库接口】


前言

       该篇教程主要关注MyBatis实现底层的接口,把MyBatis交给Spring来托管。数据库连接池用的c3p0。数据库用的MySQL。主要有2个大类:秒杀商品的查询、秒杀明细的插入。

准备工作

     

      1、数据库脚本。先初始化数据库,这里主要有2张表:seckill【秒杀商品表】、success_killed【秒杀记录明细表】。success_killed采用双主键seckill_id、user_phone。同一个商品同一个手机号只能秒杀一次,如果通过非法手段通过业务接口的话,则重复插入秒杀记录明细时会返回0。

-- 创建数据库
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 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,number,start_time,end_time)
VALUES
  ('1000元秒杀iphone6',100,'2016-01-01 00:00:00','2016-01-02 00:00:00'),
  ('800元秒杀ipad',200,'2016-01-01 00:00:00','2016-01-02 00:00:00'),
  ('6600元秒杀mac book pro',300,'2016-01-01 00:00:00','2016-01-02 00:00:00'),
  ('7000元秒杀iMac',400,'2016-01-01 00:00:00','2016-01-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` TIMESTAMP NOT NULL COMMENT '创建时间',
  PRIMARY KEY(seckill_id,user_phone),/*联合主键*/
  KEY idx_create_time(create_time)
)ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表';

   2、实现MyBatis配置文件并且交由Spring托管

mybatis-config.xml

<?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>
       
       <setting name="useGeneratedKeys" value="true"/>
       
       <setting name="useColumnLabel" value="true"/>
       
       <setting name="mapUnderscoreToCamelCase" value="true"/>
   settings>
configuration>

spring-dao.xml

   这里关键是sqlsessionfactory的配置,需要指定mybatis全局配置文件、mapper.xml文件位置。

<?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">

    
    <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.username}"/>
        <property name="password" value="${jdbc.password}"/>

        
        <property name="maxPoolSize" value="30" />
        
        <property name="minPoolSize" value="10"/>
        
        <property name="autoCommitOnClose" value="false"/>
        
        <property name="checkoutTimeout" value="1000"/>
        
        <property name="acquireRetryAttempts" value="3"/>
    bean>

    
    <bean id="sessionfactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        
        <property name="typeAliasesPackage" value="com.seckill.entity"/>
        
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        
        <property name="basePackage" value="com.seckill.dao"/>
        
        <property name="sqlSessionFactoryBeanName" value="sessionfactory"/>
    bean>
beans>

秒杀底层接口实现

1、实现接口。这里注意Param注解,当方法只有一个参数时不用指定,如果你需要给mapper里传多个参数则指定,也可以用HashMap传参。

public interface SeckillDao {

    /**减库存**/
    int reduceNumber(@Param("seckillId") long seckillId,@Param("killTime") Date killTime);

    /**查询秒杀商品详情**/
    Seckill queryById(long seckillId);

    /**查询所有秒杀商品**/
    List queryAll(@Param("offset") int offset,@Param("limit") int limit);

}


public interface SuccessKillDao {

    /**
     * 插入秒杀商品明细
     * **/
    int insertSuccessKilled(@Param("seckillId") long seckillId,@Param("userPhone")  long userPhone);

    /**
     * 根据商品id查询商品秒杀明细,并且同时返回商品明细
     * **/
    SuccessKilled queryByIdWithSeckill(@Param("seckillId") long seckillId,@Param("userPhone")  long userPhone);

}

2、秒杀实现。也就是mapper目录下的*.xml文件。

SeckillDao.xml

<?xml version="1.0" encoding="UTF-8" ?>


    
        update seckill set number=number-1
        where seckill_Id=#{seckillId}
        and start_time  #{killTime}
        and end_time = ]]> #{killTime}
        and number>0
    
    
    
    
    

SuccessKillDao.xml

<?xml version="1.0" encoding="UTF-8" ?>




    
    

        insert ignore into  success_killed (seckill_id,user_Phone,state) values (#{seckillId},#{userPhone},0)
    

    

  3、OK,准备工作就绪,可以实现单元测试的方法了。

相关