zoukankan      html  css  js  c++  java
  • SSM实战——秒杀系统之DAO层实体定义、接口设计、mybatis映射文件编写、整合Spring与Mybatis

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

  • 相关阅读:
    【设计模式】迭代器模式
    SpringMVC+Hibernate+Junit4+json基本框架近乎0配置
    Python
    Flex中TabNavigator隐藏和显示选项卡
    Android调试工具_ Stetho
    discuz的php7版本号
    分组加密的四种模式(ECB、CBC、CFB、OFB)
    人件札记:保持高效的办公室环境
    UVA 4857 Halloween Costumes 区间背包
    相机标定(Camera calibration)
  • 原文地址:https://www.cnblogs.com/ygj0930/p/6905871.html
Copyright © 2011-2022 走看看