基於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>
       <!--使用jdbc的getGeneratedKeys獲取自增主鍵值-->
       <setting name="useGeneratedKeys" value="true"/>
       <!--使用列別名替換列名,默認值true-->
       <setting name="useColumnLabel" value="true"/>
       <!--開啟駝峰命名法 字段名seckill_Id 對應屬性名seckillId -->
       <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">

    <!--1、配置數據庫相關參數-->
    <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}"/>

        <!--數據庫連接池最大連接數-->
        <property name="maxPoolSize" value="30" />
        <!--數據庫連接池最小連接數-->
        <property name="minPoolSize" value="10"/>
        <!--關閉連接后不自動commit-->
        <property name="autoCommitOnClose" value="false"/>
        <!--獲取連接超時時間-->
        <property name="checkoutTimeout" value="1000"/>
        <!--當獲取連接失敗時重試次數-->
        <property name="acquireRetryAttempts" value="3"/>
    </bean>

    <!--3、配置SqlSessionFactory-->
    <bean id="sessionfactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--mybatis全局配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--掃描entity包-->
        <property name="typeAliasesPackage" value="com.seckill.entity"/>
        <!--掃描sql xml文件-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <!--4、配置掃描Dao接口包,動態實現dao接口注入到spring容器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--需要掃描的dao接口-->
        <property name="basePackage" value="com.seckill.dao"/>
        <!--注入sqlsessionfactory-->
        <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<Seckill> 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" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.seckill.dao.SeckillDao">
    <update id="reduceNumber">
        update seckill set number=number-1
        where seckill_Id=#{seckillId}
        and start_time <![CDATA[ <= ]]> #{killTime}
        and end_time <![CDATA[ >= ]]> #{killTime}
        and number>0
    </update>
    
    <select id="queryById" resultType="Seckill">
        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
        limit #{offset},#{limit}
    </select>
</mapper>

SuccessKillDao.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="com.seckill.dao.SuccessKillDao">


    <!--主鍵重復時不再插入數據-->
    <insert id="insertSuccessKilled">

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

    <select id="queryByIdWithSeckill" resultType="SuccessKilled">
        select
        sk.seckill_id,
        sk.user_Phone,
        sk.state,
        sk.create_time,
        s.seckill_id "seckill.seckill_id",
        s.name "seckill.name",
        s.number "seckill.number",
        s.create_time "seckill.create_time",
        s.start_time "seckill.start_time",
        s.end_time "seckill.end_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>

  3、OK,准備工作就緒,可以實現單元測試的方法了。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM