最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • 整合SSM框架的高并发和商品秒杀项目(一)

    一个整合SSM框架的高并发和商品秒杀项目,学习目前较流行的Java框架组合实现高并发秒杀API

    项目开发流程

    本项目很适合学习一些技术的基础,这个项目的开发分为几个流程,很基础地教你接触到一个相对有技术含量的项目
    1. Java高并发秒杀API之业务分析与DAO层
    2. Java高并发秒杀API之web层
    3. Java高并发秒杀API之Service层
    4. Java高并发秒杀API之高并发优化

    按照上面几个流程走下去,你要有基本的Maven认识以及Java语法的一些概念,要不然可能不太理解
    其实这几个流程也就是开发的流程,首先从DAO层开始开发,从后往前开发,开始Coding吧!
    项目总结可能比较长,由于公众号文章的字数限制今天只能先讲解第一节,如果这篇文章看得人多并且点赞数较高的话明天就继续更新,哈哈~

    项目环境的搭建

    • 操作系统 : Ubuntu 17.04
    • IDE :IntelliJ IDEA 2016.2.5 x64 用Eclipse也一样的,工具时靠人用的
    • JDK : JDK1.8 建议使用JDK1.7以上版本,有许多语法糖用着挺舒服的
    • Web容器 : Tomcat 8.0
    • 数据库 :Mysql-5.6.17-WinX64 实验性的项目用Mysql就足够啦
    • 依赖管理工具 : Maven 管理jar包真的很方便
      这里列出的环境不是必须的,你喜欢用什么就用什么,这里只是给出参考,不过不同的版本可能会引起各种不同的问题就需要我们自己去发现以及排查,在这里使用Maven的话时方便我们管理JAR包,我们不用跑去各种开源框架的官网去下载一个又一个的JAR包,配置好了Maven后添加pom文件坐标就会从中央仓库下载JAR包,如果哪天替换版本也很方便

    项目效果图

    秒杀商品列表

    秒杀结束提示界面

    开始秒杀提示界面

    重复秒杀提示界面


    秒杀成功提示界面

    项目的运行

    下载

    Download Zip或者 git clone
    git clone https://github.com/Sunybyjava/seckill.git

    导入到IDE

    这里因为是使用IDEA创建的项目,所以使用IDEA直接打开是很方便的,提前是你要配置好maven的相关配置,以及项目JDK版本,JDK版本必须在1.8以上,因为在项目中使用了Java8LocalDateTime以及LocalDate,所以低于这个版本编译会失败的
    • IDEA
      直接在主界面选择Open,然后找到项目所在路径,点击pom.xml打开就可以了
    • Eclipse 这个项目是基于IDEA创建,我这里把项目转成了Eclipse的项目,如果你使用Eclipse的话也可以直接导入,只是步骤更繁琐一点,Eclipse导入步骤

    (一)Java高并发秒杀APi之业务分析与DAO层代码编写

    构建项目的基本骨架

    • 首先我们要搭建出一个符合Maven约定的目录来,这里大致有两种方式,第一种:
    1. 第一种使用命令行手动构建一个maven结构的目录,当然我基本不会这样构建

    mvn archetype:generate -DgroupId=com.suny.seckill -DartifactId=seckill -Dpackage=com.suny.seckill -Dversion=1.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp

    这里要注意的是使用archetype:generate进行创建,在Maven老版本中是使用archetype:create,现在这种方法已经被弃用了,所以使用命令行创建的话注意了,稍微解释下这段语句的意思,就是构建一个一个maven-archetype-webapp骨架的Webapp项目,然后groupIdcom.suny.seckill ,artifactIdseckill,这里是Maven相关知识,可以按照自己的情况进行修改
    2.第二种直接在IDE中进行创建,这里以IDEA为例
    • 点击左上角File>New>Project>Maven
    • 然后在里面勾选Create from archetype,然后再往下拉找到org.apache.cocoon:cocoon-22-archetype-webapp,选中它,注意要先勾选那个选项,否则选择不了,然后点击Next继续


    +然后就填写你的Maven的那几个重要的坐标了,自己看着填吧

    +再就配置你的Maven的相关信息,默认应该是配置好的

    +之后就是点Finsh,到此不出意外的话就应该创建成功了

    构建pom文件

    项目基本的骨架我们就创建出来了,接下来我们要添加一些基本的JAR包的依赖,也就是在pom.xml中添加各种开源组件的三坐标了
    <projectxmlns=“http://maven.apache.org/POM/4.0.0”xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
          xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd”>
           <modelVersion>4.0.0</modelVersion>
           <groupId>com.suny.seckill</groupId>
           <artifactId>seckill</artifactId>
           <version>1.0-SNAPSHOT</version>
           <name>seckill Maven Webapp</name>
           <url>http://maven.apache.org</url>
     <dependencies>

         <!–junit测试–>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>

         <!–配置日志相关,日志门面使用slf4j,日志的具体实现由logback实现–>
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <version>1.1.7</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>1.7.21</version>
         </dependency>
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-core</artifactId>
             <version>2.6.1</version>
         </dependency>

         <!–数据库相关依赖–>
         <!–首先导入连接Mysql数据连接–>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.39</version>
         </dependency>

         <!–导入数据库连接池–>
         <dependency>
             <groupId>c3p0</groupId>
             <artifactId>c3p0</artifactId>
             <version>0.9.1.2</version>
         </dependency>

         <!–导入mybatis依赖–>
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.4.2</version>
         </dependency>
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis-spring</artifactId>
             <version>1.3.1</version>
         </dependency>

         <!–导入Servlet web相关的依赖–>
         <dependency>
             <groupId>taglibs</groupId>
             <artifactId>standard</artifactId>
             <version>1.1.2</version>
         </dependency>
         <dependency>
             <groupId>jstl</groupId>
             <artifactId>jstl</artifactId>
             <version>1.2</version>
         </dependency>
         <!–spring默认的json转换–>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             <version>2.8.5</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>3.1.0</version>
         </dependency>
         
         <!–导入spring相关依赖–>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
             <version>4.3.6.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-beans</artifactId>
             <version>4.3.6.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
             <version>4.3.6.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-jdbc</artifactId>
             <version>4.3.7.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-tx</artifactId>
             <version>4.3.6.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-web</artifactId>
             <version>4.3.6.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
             <version>4.3.7.RELEASE</version>
         </dependency>
         
         <!–导入springTest–>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
             <version>4.2.7.RELEASE</version>
         </dependency>
     </dependencies>
     <build>
         <finalName>seckill</finalName>
     </build>
    </project>

    建立数据库

    在根目录下有一个sql文件夹里面有一个sql数据库脚本,如果你不想自己手写的话就直接导入到你的数据库里面去吧,不过还是建议自己手写一遍加深印象
    — 整个项目的数据库脚本
    — 开始创建一个数据库
    CREATEDATABASE seckill;
    — 使用数据库
    USE seckill;
    — 创建秒杀库存表
    CREATETABLE seckill(
     `seckill_id`BIGINTNOTNULL AUTO_INCREMENT COMMENT‘商品库存ID’,
     `name`VARCHAR(120) NOTNULLCOMMENT‘商品名称’,
     `number`INTNOTNULLCOMMENT‘库存数量’,
     `start_time`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP() COMMENT‘秒杀开启的时间’,
     `end_time`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP() COMMENT‘秒杀结束的时间’,
     `create_time`TIMESTAMPNOTNULLDEFAULTCURRENT_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=1000DEFAULTCHARSET=utf8 COMMENT=‘秒杀库存表’;

    — 插入初始化数据

    insertinto
     seckill(name,number,start_time,end_time)
    values
     (‘1000元秒杀iphone6’,100,‘2016-5-22 00:00:00’,‘2016-5-23 00:00:00’),
     (‘500元秒杀iPad2’,200,‘2016-5-22 00:00:00’,‘2016-5-23 00:00:00’),
     (‘300元秒杀小米4’,300,‘2016-5-22 00:00:00’,‘2016-5-23 00:00:00’),
     (‘200元秒杀红米note’,400,‘2016-5-22 00:00:00’,‘2016-5-23 00:00:00’);

    — 秒杀成功明细表
    — 用户登录相关信息
    createtable success_killed(
     `seckill_id`BIGINTNOTNULLCOMMENT‘秒杀商品ID’,
     `user_phone`BIGINTNOTNULLCOMMENT‘用户手机号’,
     `state` TINYINT NOTNULLDEFAULT-1COMMENT‘状态标示:-1无效 0成功 1已付款’,
     `create_time`TIMESTAMPNOTNULLCOMMENT‘创建时间’,
     PRIMARY KEY (seckill_id,user_phone), /*联合主键*/
     KEY idx_create_time(create_time)
    )ENGINE =InnDB DEFAULTCHARSET =utf8 COMMENT =‘秒杀成功明细表’

    在建立数据库的,如果按照我这里的数据库脚本建立的话应该是没问题的,但是我按照视频里面的数据库脚本建表的话发生了一个错误

    这个报错看起来比较的诡异,我仔细检查sql也没有错误,它总提示我end_time要有一个默认的值,可我记得我以前就不会这样,然后视频里面也没有执行错误,然后我感觉可能时MySQL版本的差异,我查看了下我数据库版本,在登录Mysql控制台后输入指令,在控制台的我暂时知道的有两种方式:

    selectversion();  
    select @@version;

    我的输出结果如下: 

    进控制台就已经可以看到版本了,我的Mysql是5.7的,以前我用的时5.6的,然后去Google上搜索了下,找到了几个答案,参考链接:
    • https://stackoverflow.com/questions/9192027/invalid-default-value-for-create-date-timestamp-field
    • mysql官方的解释:https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_date
    • https://stackoverflow.com/questions/34570611/mysql-community-5-7-invalid-default-value-datetime-field-type

    总结出来一句话就是:

    mysql 5.7中,默认使用的是严格模式,这里的日期必须要有时间,所以一定要给出默认值,要么就修改数据库设置
    然后网友评论里总结出来的几种解决办法,未经测试!:
    • 下次有问题一定要先看一下评论!!!create不了的同学,可以这样写:

    `start_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT‘秒杀开始时间’,
      `end_time`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT‘秒杀结束时间’,
      `create_time`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT‘创建时间’,

    • 关于timestamp的问题,需要先运行 set explicit_defaults_for_timestamp = 1,否则会报invalid default value错误
    • 还需要注意的是SQL版本的问题会导致视频中seckill表创建会出错。只要将create_time放在start_time和end_time之前是方便的解决方法。

    对比下我修改过后的跟视频里面的sql片段: 

    我们可以看到在这三个字段有一个小差别,那就是给start_time,end_time,create_time三个字段都添加一个默认值,然后执行数据库语句就没问题了

    这里我们需要修改下web.xml中的servlet版本为3.0

    打开WEB-INF下的web.xml,修改为以下代码:
    <web-appxmlns=“http://java.sun.com/xml/ns/javaee”
            xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
            xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee
                         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd”
            version=“3.0”
            metadata-complete=“true”>
       <!–用maven创建的web-app需要修改servlet的版本为3.0–>

    修改的原因有以下几点:
    • 高版本的Servlet支持更多的特性,更方便我们的Coding,特别是支持注解这一特性
    • Servlet2.3中新加入了Listener接口的实现,,我们可以使用Listener引入SpringContextLoaderListener
    举个栗子:
    • Servlet2.3以前我们这样配置ContextLoaderListener:

    <servlet>
    <servlet-name>context</servlet-name>
    <servlet-class>org.springframework.context.ContextLoaderServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    • Servlet2.3以后可以使用Listener配置,也就是我们项目中使用的方法

    <listener>
    <listener-class>org.springframework.context.ContextLoaderListener</listener-class>
    </listener>

    两种方法的效果都是一样的,主要不要同时使用,否则会报错的

    建立实体类

    • 首先建立SuccessKilled 秒杀状态表

    package com.suny.entity;

    import java.io.Serializable;
    import java.time.LocalDateTime;


    publicclassSuccessKilledimplementsSerializable{
       privatestaticfinallong serialVersionUID = 1834437127882846202L;

       privatelong seckillId;
       /* 用户的手机号码*/
       privatelong userPhone;
       /* 秒杀的状态*/
       privateshort state;
       /* 创建时间*/
       private LocalDateTime createTime;
       /* 多对一,因为一件商品在库存中肯定有许多,对应的购买信息也有很多*/
       private Seckill seckill;

       publicSuccessKilled(){
       }

       publicSuccessKilled(long seckillId, long userPhone, short state, LocalDateTime createTime, Seckill seckill){
           this.seckillId = seckillId;
           this.userPhone = userPhone;
           this.state = state;
           this.createTime = createTime;
           this.seckill = seckill;
       }

       publiclonggetSeckillId(){
           return seckillId;
       }

       publicvoidsetSeckillId(long seckillId){
           this.seckillId = seckillId;
       }

       publiclonggetUserPhone(){
           return userPhone;
       }

       publicvoidsetUserPhone(long userPhone){
           this.userPhone = userPhone;
       }

       publicshortgetState(){
           return state;
       }

       publicvoidsetState(short state){
           this.state = state;
       }

       public LocalDateTime getCreateTime(){
           return createTime;
       }

       publicvoidsetCreateTime(LocalDateTime createTime){
           this.createTime = createTime;
       }

       public Seckill getSeckill(){
           return seckill;
       }

       publicvoidsetSeckill(Seckill seckill){
           this.seckill = seckill;
       }

       @Override
       public String toString(){
           return“SuccessKilled{“ +
                   “主键ID=” + seckillId +
                   “, 手机号码=” + userPhone +
                   “, 秒杀状态=” + state +
                   “, 创建时间=” + createTime +
                   “, 秒杀的商品=” + seckill +
                   ‘}’;
       }
    }

    • 再建立Seckill 秒杀商品信息

    package com.suny.entity;

    import java.io.Serializable;
    import java.time.LocalDateTime;

    publicclassSeckillimplementsSerializable{

       privatestaticfinallong serialVersionUID = 2912164127598660137L;
       /* 主键ID*/
       privatelong seckillId;
       /*  秒杀商品名字 */
       private String name;
       /* 秒杀的商品编号 */
       privateint number;
       /* 开始秒杀的时间 */
       private LocalDateTime startTime;
       /* 结束秒杀的时间 */
       private LocalDateTime endTime;
       /* 创建的时间 */
       private LocalDateTime createTIme;

       publicSeckill(){
       }

       publicSeckill(long seckillId, String name, int number, LocalDateTime startTime, LocalDateTime endTime, LocalDateTime createTIme){
           this.seckillId = seckillId;
           this.name = name;
           this.number = number;
           this.startTime = startTime;
           this.endTime = endTime;
           this.createTIme = createTIme;
       }

       publiclonggetSeckillId(){
           return seckillId;
       }

       publicvoidsetSeckillId(long seckillId){
           this.seckillId = seckillId;
       }

       public String getName(){
           return name;
       }

       publicvoidsetName(String name){
           this.name = name;
       }

       publicintgetNumber(){
           return number;
       }

       publicvoidsetNumber(int number){
           this.number = number;
       }

       public LocalDateTime getStartTime(){
           return startTime;
       }

       publicvoidsetStartTime(LocalDateTime startTime){
           this.startTime = startTime;
       }

       public LocalDateTime getEndTime(){
           return endTime;
       }

       publicvoidsetEndTime(LocalDateTime endTime){
           this.endTime = endTime;
       }

       public LocalDateTime getCreateTIme(){
           return createTIme;
       }

       publicvoidsetCreateTIme(LocalDateTime createTIme){
           this.createTIme = createTIme;
       }

       @Override
       public String toString(){
           return“com.suny.entity.Seckill{“ +
                   “主键ID=” + seckillId +
                   “, 秒杀商品='” + name + ”’ +
                   “, 编号=” + number +
                   “, 开始秒杀时间=” + startTime +
                   “, 结束秒杀时间=” + endTime +
                   “, 创建时间=” + createTIme +
                   ‘}’;
       }

    }


    对实体类创建对应的mapper接口,也就是dao接口类
    • 首先创建SeckillMapper,在我这里位于com.suny.dao包下

    package com.suny.dao;

    import com.suny.entity.Seckill;
    import org.apache.ibatis.annotations.Param;

    import java.time.LocalDateTime;
    import java.util.List;

    publicinterfaceSeckillMapper{
      /**
       * 根据传过来的<code>seckillId</code>去减少商品的库存.
       *
       * @param seckillId 秒杀商品ID
       * @param killTime  秒杀的精确时间
       * @return 如果秒杀成功就返回1,否则就返回0
       */
      intreduceNumber(@Param(“seckillId”)long seckillId, @Param(“killTime”) LocalDateTime killTime);

      /**
       * 根据传过来的<code>seckillId</code>去查询秒杀商品的详情.
       *
       * @param seckillId 秒杀商品ID
       * @return 对应商品ID的的数据
       */
      Seckill queryById(@Param(“seckillId”)long seckillId);

      /**
       * 根据一个偏移量去查询秒杀的商品列表.
       *
       * @param offset 偏移量
       * @param limit  限制查询的数据个数
       * @return 符合偏移量查出来的数据个数
       */
      List<Seckill> queryAll(@Param(“offset”)int offset, @Param(“limit”)int limit);
    }

    • 再创建SuccessKilledMapper

    packagecom.suny.dao;

    importcom.suny.entity.SuccessKilled;
    importorg.apache.ibatis.annotations.Param;


    publicinterfaceSuccessKilledMapper {
      /**
       * 插入一条详细的购买信息.
       *
       * @param seckillId 秒杀商品的ID
       * @param userPhone 购买用户的手机号码
       * @return 成功插入就返回1, 否则就返回0
       */
      intinsertSuccessKilled(@Param(“seckillId”) long seckillId, @Param(“userPhone”) long userPhone);

      /**
       * 根据秒杀商品的ID查询<code>SuccessKilled</code>的明细信息.
       *
       * @param seckillId 秒杀商品的ID
       * @param userPhone 购买用户的手机号码
       * @return 秒杀商品的明细信息
       */
      SuccessKilledqueryByIdWithSeckill(@Param(“seckillId”) long seckillId, @Param(“userPhone”) long userPhone);

    }


    接下来书写xml配置文件
    建立对应的mapper.xml
    首先在src/main/resources建立com.suny.dao这个包,也就是对应mapper接口文件包一样的包名,这样符合Maven的约定,就是资源放置在Resource包下,Java包下则是放置java类文件,编译后最后还是会在同一个目录下

    • 首先建立SeckillMapper.xml

    <!DOCTYPE mapper
           PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN”
           “http://mybatis.org/dtd/mybatis-3-mapper.dtd”>
    <mappernamespace=“com.suny.dao.SeckillMapper”>
       <!–这里的<=需要使用进行忽略,所以是要进行忽略,使用CDATA 区段中的文本会被解析器忽略 –>
       <updateid=“reduceNumber”>
           UPDATE seckill
           SET number = number – 1
           WHERE seckill_id = #{seckillId}
                 AND start_time
                 <![CDATA[
                 <=
                 ]]>
            #{killTime}
                 AND end_time >= #{killTime}
                 AND number > 0
       </update>

       <selectid=“queryById”resultType=“com.suny.entity.Seckill”>
           SELECT
               *
           FROM seckill AS s
           WHERE s.seckill_id = #{seckillId}
       </select>


       <selectid=“queryAll”resultType=“com.suny.entity.Seckill”>
           SELECT
               *
           FROM seckill AS s
           ORDER BY create_time DESC
           LIMIT #{offset}, #{limit}
       </select>
    </mapper>

    • 建立SuccessKilledMapper.xml

    <!DOCTYPE mapper
           PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN”
           “http://mybatis.org/dtd/mybatis-3-mapper.dtd”>
    <mappernamespace=“com.suny.dao.SuccessKilledMapper”>
       <!–添加主键冲突时忽略错误返回0–>  
       <insertid=“insertSuccessKilled”>
           INSERT IGNORE INTO success_killed (seckill_id, user_phone, state)
           VALUES (#{seckillId}, #{userPhone}, 0)
       </insert>
       <!–根据seckillId查询SuccessKilled对象,并携带Seckill对象,告诉mybatis把映射结果映射到SuccessKill属性同时映射到Seckill属性–>  
       <selectid=“queryByIdWithSeckill”resultType=“com.suny.entity.SuccessKilled”>
           SELECT
               sk.seckill_id,
               sk.user_phone,
               sk.create_time,
               sk.state,
               s.seckill_id  “seckill.seckill_id”,
               s.name “seckill.name”,
               s.number “seckill”,
               s.start_time  “seckill.start_time”,
               s.end_time  “seckill.end_time”,
               s.create_time “seckill.create_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>

    • 建立Mybatis的配置文件mybatis-config.xml

    <?xml version=“1.0” encoding=“UTF-8”?>
    <!DOCTYPE configuration PUBLIC
           “-//mybatis.org//DTD MyBatis Generator Configuration 3.0//EN”
           “http://mybatis.org/dtd/mybatis-3-config.dtd” >
    <configuration>
       <!–首先配置全局属性–>
       <settings>
           <!–开启自动填充主键功能,原理时通过jdbc的一个方法getGeneratekeys获取自增主键值–>
           <settingname=“useGeneratedKeys”value=“true”/>
           <!–使用别名替换列名,默认就是开启的–>
           <settingname=“useColumnLabel”value=“true”/>
           <!–开启驼峰命名的转换–>
           <settingname=“mapUnderscoreToCamelCase”value=“true”/>
       </settings>
    </configuration>

    • 然后建立连接数据库的配置文件jdbc.properties,这里的属性要根据自己的需要去进行修改,切勿直接复制使用

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.user=root
    jdbc.password=root
    jdbc.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8

    • 建立Springdao的配置文件,在resources包下创建applicationContext-dao.xml

    <?xml version=“1.0” encoding=“UTF-8”?>
    <!–suppress SpringFacetInspection –>
    <beansxmlns=“http://www.springframework.org/schema/beans”
          xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
          xmlns:context=“http://www.springframework.org/schema/context”
          xmlns:tx=“http://www.springframework.org/schema/tx”
          xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd”>
       <context:property-placeholderlocation=“classpath:jdbc.properties”/>

       <!–配置数据库连接池–>
       <beanid=“dataSource”class=“com.mchange.v2.c3p0.ComboPooledDataSource”>
           <!–配置基本的数据库连接–>
           <propertyname=“driverClass”value=“${jdbc.driver}”/>
           <propertyname=“jdbcUrl”value=“${jdbc.url}”/>
           <propertyname=“user”value=“${jdbc.user}”/>
           <propertyname=“password”value=“${jdbc.password}”/>
           <!–c3p0私有属性–>
           <propertyname=“maxPoolSize”value=“30”/>
           <propertyname=“minPoolSize”value=“10”/>
           <!–关闭连接后不自动commit–>
           <propertyname=“autoCommitOnClose”value=“false”/>
           <!–获取连接超时时间–>
           <propertyname=“checkoutTimeout”value=“1000”/>
           <!–当获取连接失败时的重试次数–>
       </bean>
       <!–配置sqlSessionFactory对象–>
       <beanid=“sqlSessionFactory”class=“org.mybatis.spring.SqlSessionFactoryBean”>
           <!–注入数据库连接池–>
           <propertyname=“dataSource”ref=“dataSource”/>
           <!–配置mybatis全局配置文件–>
           <propertyname=“configLocation”value=“mybatis-config.xml”/>
           <!–配置entity包,也就是实体类包,自动扫描,用于别名配置–>
           <propertyname=“typeAliasesPackage”value=“com.suny.entity”/>
           <!–配置需要扫描的mapper.xml文件–>
           <propertyname=“mapperLocations”value=“classpath*:com/suny/dao/*.xml”/>
       </bean>

       <!–配置mapper接口包,动态实现mapper接口,注入到Spring容器–>
       <beanclass=“org.mybatis.spring.mapper.MapperScannerConfigurer”>
           <!–注入sqlSessionFactory,请注意不要使用sqlSessionFactoryBean,否则会出现注入异常–>
           <propertyname=“sqlSessionFactoryBeanName”value=“sqlSessionFactory”/>
           <!–给出要扫描的mapper接口–>
           <propertyname=“basePackage”value=“com.suny.dao”/>
       </bean>

    </beans>

    • 基础的部分我们搭建完成了,然后要开始测试了 在IDEA里面有一个快速建立测试的快捷键Ctrl+Shift+T,在某个要测试的类里面按下这个快捷键就会出现Create new Test,然后选择你要测试的方法跟测试的工具就可以了,这里我们使用Junit作为测试

      建立SeckillMapperTest文件,代码如下

    package com.suny.dao;

    import com.suny.entity.Seckill;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    import javax.annotation.Resource;

    import java.time.LocalDateTime;
    import java.util.List;

    importstatic org.junit.Assert.*;


    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({“classpath:spring/applicationContext-dao.xml”})
    publicclassSeckillMapperTest{
      @Resource
      private SeckillMapper seckillMapper;

      @Test
      publicvoidreduceNumber()throws Exception {
          long seckillId=1000;
          LocalDateTime localDateTime=LocalDateTime.now();
          int i = seckillMapper.reduceNumber(seckillId, localDateTime);
          System.out.println(i);
      }

      @Test
      publicvoidqueryById()throws Exception {
          long seckillId = 1000;
          Seckill seckill = seckillMapper.queryById(seckillId);
          System.out.println(seckill.toString());
      }

      @Test
      publicvoidqueryAll()throws Exception {
          List<Seckill> seckills = seckillMapper.queryAll(0, 100);
          for (Seckill seckill : seckills) {
              System.out.println(seckill.toString());
          }
      }

    }

    测试中可能会出现Mybatis参数绑定失败的错误,在mapper接口中的方法里面添加@Param的注解,显示的告诉mybatis参数的名称是什么,例如

    List<Seckill> queryAll(@Param(“offset”) int offset, @Param(“limit”) int limit);


    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » 整合SSM框架的高并发和商品秒杀项目(一)

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 169会员总数(位)
    • 3735资源总数(个)
    • 1本周发布(个)
    • 0 今日发布(个)
    • 443稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级