秒杀系统项目体系结构(Dao层)
pom.xml文件
xmlns="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">
4.0.0
com.seckill
seckill
war
1.0-SNAPSHOT
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.1
ch.qos.logback
logback-classic
1.1.1
mysql
mysql-connector-java
5.1.37
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
mybatis-config.xml配置
xml version="1.0" encoding="UTF-8" ?> configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">name="useGeneratedKeys" value="true"/> name="useColumnLabel" value="true"/> name="mapUnderscoreToCamelCase" value="true"/>
spring-dao.xml配置(主要配置的是Spring的dao层的相关配置,包括和mybatis的整合)
xml version="1.0" encoding="UTF-8"?>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"/> id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> name="driverClass" value="${jdbc.driver}"/> name="jdbcUrl" value="${jdbc.url}"/> name="user" value="${jdbc.username}"/> name="password" value="${jdbc.password}"/> name="maxPoolSize" value="30"/> name="minPoolSize" value="10"/> name="autoCommitOnClose" value="false"/> name="checkoutTimeout" value="1000"/> name="acquireRetryAttempts" value="5"/> id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> name="dataSource" ref="dataSource"/> name="configLocation" value="classpath:mybatis-config.xml"/> name="typeAliasesPackage" value="com.seckill.entity"/> name="mapperLocations" value="classpath:mapper/*.xml"/> class="org.mybatis.spring.mapper.MapperScannerConfigurer"> name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> name="basePackage" value="com.seckill.dao"/>
这是一个mapper.xml的文件,要注意其中的<=的表示是有所不同的
xml version="1.0" encoding="UTF-8" ?> mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">namespace="com.seckill.dao.SeckillDao"> id="reduceNumber"> /*具体的SQL语句*/ UPDATE seckill SET number = number-1 WHERE seckill_id = #{seckillId} and start_time #{killTime}, and end_time >= #{killTime}, and number > 0;
dao层的一个类(只写接口,在给一个方法添加注释的时候使用的快捷键是AIL+Enter,在形参是两个及两个以上的的时候要使用@Param()来进行标示,一个的使用可以不用。
package com.seckill.dao; import com.seckill.entity.Seckill; import org.apache.ibatis.annotations.Param; import java.util.Date; import java.util.List; /** * Created by WangKai's Hands. * User:WangKai * Date:2018/2/21 * Time:15:06 * Email: [email protected] */ /*有关Seckill的Dao层接口*/ public interface SeckillDao { /** * 减库存 * @param seckillId * @param killTime * @return 如果影响行数>1表示的是更新的记录行数。 */ int reduceNumber(@Param("seckillId") long seckillId,@Param("killTime") Date killTime); /** * 按照商品id来查询商品对象 * @param seckillId * @return */ Seckill queryById(long seckillId); /** * 根据偏移量来查询秒杀商品的列表 * @param offset * @param limit * @return */ ListqueryAll(@Param("offset") int offset,@Param("limit") int limit); }
jdbc.properties配置
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=123456
必须按照官网的这个方式来!惨痛的教训惨痛的教训
下面的是一个Junit的测试类,这也是出现的最大的问题就是JDBC一直连接不上,主要的问题就是视频上面的和官网上面的配置的时候有些是不同的 ,就比如说这个jdbc.url。惨痛的教训,特此贴一个博客,谢谢这位哥们:
http://blog.csdn.net/sinat_27406925/article/details/70666380
package com.seckill.dao; import com.seckill.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.util.Date; import java.util.List; import static org.junit.Assert.*; /** * Created by WangKai's Hands. * User:WangKai * Date:2018/2/21 * Time:22:25 * Email: [email protected] */ /* * 配置Spring和Junit的整合,是为了能够在JUnit的启动的时候我们能够自动的加载SpringIOC的容器 * 我们有两个依赖分别是spring-test,junit * */ //RunWith 是一Junit依赖,作用是在Junit启动的时候去加载我们这个Spring容器 @RunWith(SpringJUnit4ClassRunner.class) //告诉junit我们的Spring的配置文件是在哪里? @ContextConfiguration({"classpath:spring/spring-dao.xml"}) public class SeckillDaoTest { //注入Dao实现依赖 @Resource private SeckillDao seckillDao; @Test /*输出结果以及mybatis的运行 23:40:33.457 [main] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@2a551a63] will not be managed by Spring 23:40:33.486 [main] DEBUG c.s.dao.SeckillDao.reduceNumber - ==> Preparing: *//*具体的SQL语句*//* UPDATE seckill SET number = number - 1 WHERE seckill_id = ? and start_time <= ? and end_time >= ? and number > 0; 23:40:33.599 [main] DEBUG c.s.dao.SeckillDao.reduceNumber - ==> Parameters: 1000(Long), 2018-02-21 23:40:33.051(Timestamp), 2018-02-21 23:40:33.051(Timestamp) 23:40:33.677 [main] DEBUG c.s.dao.SeckillDao.reduceNumber - <== Updates: 0 23:40:33.677 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4c4d362a] updateCount+=0 */ public void reduceNumber() throws Exception { Date killTime = new Date(); int updateCount = seckillDao.reduceNumber(1000L,killTime); System.out.println("updateCount+="+updateCount); } @Test public void queryById() throws Exception { long id = 1002; Seckill seckill = seckillDao.queryById(id); System.out.println(seckill.getName()); System.out.println(seckill); /* 输出结果: 300元秒杀小米4 Seckill{ seckillId=1002,name='300元秒杀小米4', number=300, startTime=Thu Nov 01 00:00:00 CST 2018, endTime=Fri Nov 02 00:00:00 CST 2018, createTime=Wed Feb 21 14:21:02 CST 2018}*/ } @Test /* * org.mybatis.spring.MyBatisSystemException: nested exception is * org.apache.ibatis.binding.BindingException: Parameter 'offset' not found. * Available parameters are [0, 1, param1, param2] * java没有保存形参的记录,queryAll(int offset,int limit)——》query(org0,org1) * */ /* *运行结果: * Seckill{seckillId=1000, name='1000元秒杀iphone6', number=0, startTime=Thu Nov 01 00:00:00 CST 2018, endTime=Fri Nov 02 00:00:00 CST 2018, createTime=Wed Feb 21 14:21:02 CST 2018} Seckill{seckillId=1001, name='500元秒杀ipad2', number=0, startTime=Thu Nov 01 00:00:00 CST 2018, endTime=Fri Nov 02 00:00:00 CST 2018, createTime=Wed Feb 21 14:21:02 CST 2018} Seckill{seckillId=1002, name='300元秒杀小米4', number=0, startTime=Thu Nov 01 00:00:00 CST 2018, endTime=Fri Nov 02 00:00:00 CST 2018, createTime=Wed Feb 21 14:21:02 CST 2018} Seckill{seckillId=1003, name='200元秒杀红米note', number=0, startTime=Thu Nov 01 00:00:00 CST 2018, endTime=Fri Nov 02 00:00:00 CST 2018, createTime=Wed Feb 21 14:21:02 CST 2018} * */ public void queryAll() throws Exception { Listseckills = seckillDao.queryAll(0,100); for (Seckill seckill:seckills) { System.out.println(seckill); } } }
手写SQL脚本:
--创建数据库seckill 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,'2018-11-01 00:00:00','2018-11-02 00:00:00'), ('500元秒杀ipad2',200,'2018-11-01 00:00:00','2018-11-02 00:00:00'), ('300元秒杀小米4',300,'2018-11-01 00:00:00','2018-11-02 00:00:00'), ('200元秒杀红米note',400,'2018-11-01 00:00:00','2018-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` TIMESTAMP NOT NULL COMMENT '创建时间', PRIMARY key(seckill_id,user_phone),/*联合主键*/ KEY idx_create_time(create_time) )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表'; --为什么手写DDL --一般我们所有的项目都会有一个schema.sql 这样的一个文件来记录每次上线的DDL修改 --上线v1.1版本 ALTER TABLE seckill; DROP INDEX idx_create_time; ADD INDEX idx_c_s(start_time,create_time); --上线v1.2 --dd1
备注:
https://docs.spring.io/spring/docs/
Spring的各个版本的官方文档
在IDEA中生成一个类的测试方法的快捷键是Ctrl+shift+t
一定要手写SQL脚本,多多实用Linux系统,不要使用MySQL的Client。
未完待续!