大家早已熟知MVC模型,所以接下来按照这个模型来写,见天介绍DAO层的搭建,由于这篇开始会涉及到大量的代码,所以文末给出Github的地址,不再贴出过多的代码。对于数据库设计和项目介绍请阅读以下两篇文章
项目整体介绍
数据库设计和项目搭建
实体类设计
这个系统主要包括两个主要的实体类:Seckill【秒杀商品的实体类】和Seckilled【秒杀成功实体类】,
Seckill(秒杀实体类)
//秒杀商品的ID
private long seckillId;
//秒杀商品的名字
private String name;
//秒杀商品的数量
private int number;
//秒杀开始的时间
private Date startTime;
//秒杀结束的时间
private Date endTime;
//秒杀创建的时间
private Date createTime;
Seckilled(秒杀成功实体类)
//秒杀的商品的ID
private long seckillId;
//秒杀用户的电话
private long userPhone;
//秒杀商品的状态
private short state;
//秒杀成功的时间
private Date creteTime;
// 多对一的复合属性
private Seckill seckill;
在秒杀成功实体类中包含一个复合属性,在设计表的时候我们就知道,seckillId是一个外键,所以在展示的时候为了能将选出来的秒杀成功的实体类中包含商品的信息我们设置一个Seckill的对象用来存储相关的信息。
DAO层接口设计
由于使用的是Mybatis,所以需要首先设计接口,主要包括两个接口一个是用来操作商品的,一个是用来操作秒杀成功相关信息的
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
*/
List<Seckill> queryAll(@Param("offset") int offset, @Param("limit") int limit);
SuccessKilledDao
/**
* 插入购买明细,可过滤重复
*
* @param seckillId
* @param userPhone
* @return 插入的行数
*
*/
int insertSuccessKilled(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
/**
* 根据id查询SuccessKilled并携带秒杀产品对象实体
*
* @param seckillId
* @param userPhone
* @return
*/
SuccessKilled queryByIdWithSeckill(@Param("seckillId") long seckillId, @Param("userPhone") long userPhone);
到这里主要的东西都介绍完了,接下来是一些配置文件的书写,包括mapper文件的书写和Spring SpringMVC Mybatis的一些配置,由于都是一些大致相同的配置,所以给出源代码的具体地址和详细的注释,如果有不明白的可以留言解答
Mapper文件配置
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="cn.icodelife.dao.SeckillDao">
<!-- 目的:为dao接口方法提供sql语句配置 -->
<update id="reduceNumber">
<!-- 具体的sql -->
UPDATE seckill
SET number = number - 1
WHERE
seckill_id = #{seckillId}
AND start_time <![CDATA[ <= ]]> #{killTime}
AND end_time >= #{killTime}
AND number > 0
</update>
<select id="queryById" resultType="Seckill" parameterType="long">
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 DESC
LIMIT #{offset},
#{limit}
</select>
</mapper>
SuccessKilledDao.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="cn.icodelife.dao.SuccessKilledDao">
<insert id="insertSuccessKilled">
<!-- 主键冲突,报错 -->
INSERT ignore INTO success_killed (seckill_id, user_phone, state)
VALUES (#{seckillId}, #{userPhone}, 0)
</insert>
<select id="queryByIdWithSeckill" resultType="SuccessKilled">
<!-- 如何告诉MyBatis把结果映射到SuccessKilled同
时映射seckill属性 -->
<!-- 可以自由控制SQL -->
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.number",
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配置文件
<?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" />
<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
数据库配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/seckill?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=
日志配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Spring配置文件
<?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">
<!-- 配置整合mybatis过程 -->
<!-- 1.配置数据库相关参数properties的属性:${url} -->
<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}" />
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30" />
<property name="minPoolSize" value="10" />
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false" />
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000" />
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2" />
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage" value="cn.icodelife.entity" />
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml" />
</bean>
<!-- 4.配置扫描Dao接口包,动态实现Dao接口,注入到soring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="cn.icodelife.dao" />
</bean>
</beans>
网友评论