一: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接口路径不一致;