一:DAO实体编码
1:首先,在src目录下,新建org.myseckill.entity包,用于存放实体类:
2:实体类设计
根据前面创建的数据库表以及映射关系,创建实体类。
表一:秒杀商品表
对应实体类:
package org.myseckill.entity; import java.util.Date; public class Seckill {
private String SeckillId; private String name; private int number; private Date startTime; private Date endTime; private Date createTime; public String getSeckillId() {
return SeckillId;
} public void setSeckillId(String seckillId) {
SeckillId = seckillId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getNumber() {
return number;
} public void setNumber(int number) {
this.number = number;
} public Date getStartTime() {
return startTime;
} public void setStartTime(Date startTime) {
this.startTime = startTime;
} public Date getEndTime() {
return endTime;
} public void setEndTime(Date endTime) {
this.endTime = endTime;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} @Override
public String toString() {
return "Seckill [SeckillId=" + SeckillId + ", name=" + name
+ ", number=" + number + ", startTime=" + startTime
+ ", endTime=" + endTime + ", createTime=" + createTime + "]";
} }
表二:秒杀成功记录表
对应实体类:
package org.myseckill.entity; import java.util.Date; public class SuccessKilled {
private long SeckillId; private long userPhone; private int state; private Date createTime; //映射关系:多对一
private Seckill seckill; public long getSeckillId() {
return SeckillId;
} public void setSeckillId(long seckillId) {
SeckillId = seckillId;
} public String getUserPhone() {
return userPhone;
} public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
} public int getState() {
return state;
} public void setState(int state) {
this.state = state;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public Seckill getSeckill() {
return seckill;
} public void setSeckill(Seckill seckill) {
this.seckill = seckill;
} @Override
public String toString() {
return "SuccessKilled [SeckillId=" + SeckillId + ", userPhone="
+ userPhone + ", state=" + state + ", createTime=" + createTime
+ ", seckill=" + seckill + "]";
} }
二:DAO类编码
1:在src.org.myseckill目录下,再新建一个包dao,用于存放dao接口。
2:编写操作seckill表的dao接口类:
package org.myseckill.dao; import java.util.Date;
import java.util.List; import org.apache.ibatis.annotations.Param;
import org.myseckill.entity.Seckill; //操作秒杀商品表,主要是增删改查
public interface SeckillDao { //删:根据秒杀的商品ID减少对应ID的商品数量
//参数使用@Param为参数值赋予一个名字,对应xml中sql语句的{参数名}
int reduceNumber(@Param("seckillId")long seckillId,@Param("killTime")Date killTime); //查:根据id查找相应商品记录,返回一个实体类
Seckill queryById(long seckillId); //查:分页查询
List<Seckill> queryAll(@Param("offset")int offset,@Param("limit")int limit); }
3:编写操作successKilled表的dao接口类:
package org.myseckill.dao; import org.apache.ibatis.annotations.Param;
import org.myseckill.entity.Seckill;
import org.myseckill.entity.SuccessKilled; public interface SuccessKilledDao { //增:增加一条秒杀成功的记录,传入秒杀的商品ID以及进行秒杀操作的手机号
int insertSuccessKilled(@Param("seckillId")long seckillId,@Param("userPhone")long userPhone);
//查:查找某用户对某商品的秒杀记录
SuccessKilled queryByIdWithSeckill(@Param("seckillId")long seckillId,@Param("userPhone")long userPhone); }
三:Mybatis映射文件编写
配置类文件一致放在src/main/resources目录下管理。
1:在resources目录下新建 mybatis-config.xml,Mybatis的全局配置文件,再创建一个文件夹mapper用于存放mybatis关于不同数据库表的操作映射文件
2:编写mybatis-config.xml
首先,到Mybatis官网上,复制配置文件的dtd头。网址:http://www.mybatis.org/mybatis-3/zh/getting-started.html
然后,配置数据源、mapper等。
<?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"/>
<!-- 开启驼峰命名转换 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
3:在mapper目录下,为对应的dao接口编写同名的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="org.myseckill.dao.SeckillDao" >
<update id="reduceNumber">
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" parameterType="long" 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" parameterType="int">
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="org.seckill.dao.SuccessKilledDao">
<insert id="insertSuccessKilled">
<!-- ignore:主键冲突时,返回0,不报错 -->
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.create_time,
sk.state,
s.seckill_id "seckill.seckill_id",//多对一关系:SuccessKilled实体中的seckill成员属性的属性值赋值
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>
四:整合Spring与Mybatis
整合的目标:更少的编码(mabatis接口无需手动实现)、更少的配置(包扫描)、dao托管(spring自动注入dao实现类)、灵活性(自定制sql语句、*传参、结果集自动转换)
1:在resources目录下新建一个文件夹spring,用于保存Spring相关的配置文件。
在spring下新建spring-dao.xml,用于整合mabatis。
在resources下新建一个jdbc.properties文件,配置数据库连接相关。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf8
username=root
password=root
2:编写spring-dao.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">
<!-- 1:配置数据库参数文件所在 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean> <!-- 2:配置数据库连接池:使用c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driver}" />
<property name="jdbcUrl" value="${url}" />
<property name="user" value="${username}" />
<property name="password" value="${password}" />
<!-- c3p0连接池的私有属性 -->
<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="2" />
</bean> <!-- 3:配置sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBatis全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 扫描entity 使用别名 -->
<property name="typeAliasesPackage" value="org.myseckill.entity"/>
<!-- 扫描sql映射文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean> <!-- 4:配置扫描 Dao接口包,由factory动态实现Dao接口,注入到Spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描的Dao接口 -->
<property name="basePackage" value="org.myseckill.dao"/>
</bean> </beans>
五:单元测试
在test/main/java下,新建包org.myseckill.dao,并创建SeckillDao的测试类:SeckillDaoTest。
package org.myseckill.dao; import java.util.Date;
import java.util.List; import javax.annotation.security.RunAs; import org.junit.Test;
import org.junit.runner.RunWith;
import org.myseckill.entity.Seckill;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/spring-dao.xml")
public class SeckillDaoTest {
//要测试SeckillDao,则定义这样一个对象,并由spring自动注入
@Autowired
private SeckillDao seckillDao; @Test
public void testQueryById(){
long id = 1000;
Seckill seckill = seckillDao.queryById(id);
System.out.println(seckill);
} @Test
public void testQueryAll(){
//java没有保存形参的记录:queryAll(int offset,int limit) --> queryAll(arg0, arg1)
//所以需要:queryAll(@Param("offset")int offset, @Param("limit")int limit);
List<Seckill> list = seckillDao.queryAll(0,100);
for (Seckill seckill:list) {
System.out.println(seckill);
}
} @Test
public void testReduceNumber(){
int updateCount = seckillDao.reduceNumber(1000, new Date());
System.out.println(updateCount);
}
}
同理,创建SuccessKilledDaoTest
package org.myseckill.dao; import org.junit.Test;
import org.junit.runner.RunWith;
import org.myseckill.dao.SuccessKilledDao;
import org.myseckill.entity.SuccessKilled;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/spring-dao.xml")
public class SuccessKilledDaoTest {
@Autowired
SuccessKilledDao successKilledDao; @Test
public void testInsertSuccessKilled(){
int insertCount = successKilledDao.insertSuccessKilled(1001, 15764210366L);
System.out.println(insertCount);
} @Test
public void testQueryByIdWithSeckill(){
SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(1000, 15764210366L);
System.out.println(successKilled);
System.out.println(successKilled.getSeckill());
} }
测试记录一:ClassNotFound:com.mysql.Driver加载失败
原因排除:
首先检查是否没导入这个jar包,由于是用maven管理的,检查pom.xml已经导入了这个包,依赖库里也已经下载;
然后检查是否下载的包损坏或版本不对:手动下载mysql-connector-java-5.1.5.jar包,拷贝到目录下并添加到buildPath,测试通过。
结论:是pom.xml中导入的jar包版本不对,换成5.1.5的即可。
测试记录二:BindingException: Invalid bound statement (not found)
Mybatis接口绑定错误:
首先检查是否dao接口中的方法与xml中配置的id名字不一;
然后检查是否xml中mapper标签的namespace属性与dao接口路径不一致;