美文网首页征服SpringJAVA_Spring
SSM学习一DAO层相关配置与实践

SSM学习一DAO层相关配置与实践

作者: kason_zhang | 来源:发表于2017-04-19 18:52 被阅读58次

    手写DDL的原因是为了升级版本时可知道对数据库具体做了哪些修改。方便工程师去了解变化。

    1 创建maven webapp项目

    修改web.xml使之支持jstl

    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
      <display-name>Archetype Created Web Application</display-name>
    </web-app>
    

    修改pom.xml,加入各种SSM所需要的配置

    <project 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">
      <modelVersion>4.0.0</modelVersion>
      <groupId>seckill</groupId>
      <artifactId>seckill</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>seckill Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <!--使用Juni4 -->
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
        <!--补全项目依赖 -->
        <!--
        1:日志 java日志:slf4j, log4j, logback, common-logging
        slf4j 是规范/接口
        日志实现: log4j,logback,common-logging
        使用: slf4j + logback
        -->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.12</version>
        </dependency>
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-core</artifactId>
          <version>1.1.1</version>
        </dependency>
        <!-- 实现slf4j接口并整合 -->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.1.1</version>
        </dependency>
    
        <!--
        2: 数据库相关依赖
        -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.35</version>
          <scope>runtime</scope>
        </dependency>
        <dependency>
          <groupId>c3p0</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.1.2</version>
        </dependency>
        <!-- DAO框架:mybatis依赖 -->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.3.0</version>
        </dependency>
        <!-- mybatis自身实现的spring整合依赖 -->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>1.2.3</version>
        </dependency>
        <!--3: Servlet web 自身依赖 -->
        <dependency>
          <groupId>taglibs</groupId>
          <artifactId>standard</artifactId>
          <version>1.1.2</version>
        </dependency>
        <dependency>
          <groupId>jstl</groupId>
          <artifactId>jstl</artifactId>
          <version>1.2</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.5.4</version>
        </dependency>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
        </dependency>
    
        <!--4: Spring依赖 -->
        <!--
        1)spring核心依赖
        -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
    
        <!--
        2)spring dao 依赖
        -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
    
        <!--
        3)spring web相关依赖
        -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
    
        <!--
        4)spring test相关依赖
        -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>4.1.7.RELEASE</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>seckill</finalName>
      </build>
    </project>
    
    

    数据 ===》 映射 ===》 对象
    其中像mybatis和hiberate都是工作在映射层的

    参数 ++++SQL = Entity/List

    Mybatis怎么用? SQL写在哪? 如何DAO接口?

    SQL写在哪?
    1, XML提供SQL(建议使用)方便维护
    2,注解提供SQL

    如何DAO接口?
    Mapper自动实现DAO接口(建议)
    API编程接口实现DAO接口

    2 配置全局mybatis

    以下配置都来自mybatis官方文档,建议学习通过官网去使用。
    在resources下建立mybatis-config.xml

    <?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>
            <!--使用JDBS的getGenerateKeys获取数据库自增主键值 -->
            <setting name="useGeneratedKeys" value="true"/>
            <!--使用列别名替换列名 默认:true
             有种场景表中的列为name然而实体中对应的确是title
             select name as title from table;
             此时mybatis会自动识别name对应的是实体中的title,然后转成实体类型
             -->
            <setting name="useColumnLabel" value="true"/>
    
            <!-- 开启驼峰命名转换 Table(create_time)===>Entity(createTime) -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    </configuration>
    

    之后建立mapper文件夹,里面分别建立对应DAO的mapper映射xml目的就是为DAO接口方法提供sql语句配置。

    3 基于mybatis实现DAO接口

    比如SeckillDao接口配置其mapper
    SeckillDao的代码:

    package seckill.dao;
    
    import org.apache.ibatis.annotations.Param;
    import seckill.entity.Seckill;
    
    import java.util.Date;
    import java.util.List;
    
    /**
     * Created by kason_zhang on 4/19/2017.
     */
    
    /**
     * 多个参数需要使用@Param
     */
    public interface SeckillDao {
    
        /**
         * 减库存
         * @param seckillId
         * @param killTime
         * @return
         */
        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);
    }
    
    

    其对应的mapper:
    <mapper>处要注明namespace,后面就是书写具体的sql语句。

    <?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="seckill.dao.SeckillDao">
    
        <!--目的:为DAO接口方法提供sql语句配置 -->
        <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" 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>
    

    再来一个DAO
    SuccessKilledDao:

    package seckill.dao;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    import static org.junit.Assert.*;
    
    /**
     * Created by kason_zhang on 4/19/2017.
     */
    /**
     * 配置Spring与Junit整合,junit启动时加载springIOC容器
     * spring-test,junit
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    //告诉Junit spring配置文件
    public class SuccessKilledDaoTest {
        @Resource
        private SuccessKilledDao successKilledDao;
        @Test
        public void insertSuccessKilled() throws Exception {
    
        }
    
        @Test
        public void queryByIdWithSeckill() throws Exception {
    
        }
    
    }
    
    

    其对应的mapper:这个mapper书写起来会比较复杂,因为SuccessKilled实体类里有Seckill属性对象。

    <?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="seckill.dao.SuccessKilledDao">
        <!--目的:为DAO接口方法提供sql语句配置 -->
        <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">
    
            <!--根据id 查询SuccessKilled并携带秒杀产品对象实体-->
            <!--如何告诉mybatis把结果映射到SuccessKilled同时映射Seckill属性 -->
            <!--可以自由控制SQL -->
            select
              sk.seckill_id,sk.user_phone,sk.state,sk.create_time,
            s.seckill_id "seckill.seckill_id" <!--这个seckill是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>
    

    4 mybatis整合Spring

    更少的编码: 只写接口,不写实现;接口能够说明很多事情(觉得命名要注意,最好可以反映你的行为)
    更少的配置: 别名(实体类的包扫描),配置扫描(自动扫描mapper配置文件),dao实现(spring 包扫描,自动实现DAO接口,自动注入spring容器)
    足够的灵活性:自己定制SQL,自由传参,结果集自动赋值

    生产环境: XML提供SQL,DAO接口提供Mapper
    查看Spring官方文档spring-framework
    查找spring配置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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 配置整合mybatis过程 -->
        <!--1: 配置数据库相关参数 -->
        
    </beans>
    

    Spring中配置mybatis总共分为四部:
    1: 配置数据库相关参数properties的属性:通过${}来获取属性值
    2:数据库连接池
    3: 配置SqlSessionFactory对象 这一步非常重要。把entity扫面和mapper.xml扫描配置进去
    4: 配置扫描DAO接口包 目的:动态实现DAO接口,并注入到Spring容器中,最能节省工作量的配置
    其中3,4两部是spring整合mybatis配置的核心能够大大节省代码工作量。

    <?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的属性:通过${}来获取属性值
        -->
        <context:property-placeholder location="classpath:jdbc.properties"/>
    
        <!--2:数据库连接池 -->
        <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,4部是配置的精华 约定大于配置-->
        <!-- 3: 配置SqlSessionFactory对象 这一步非常重要-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!--注入数据库连接池 就是上面的id=dataSource-->
            <property name="dataSource" ref="dataSource"/>
            <!-- 配置MyBatis全局配置文件: mybatis-config.xml-->
            <!--什么是classpath目录,java下的目录和resources下的目录都是classpath下的目录-->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <!-- 扫描entity包 使用别名 seckill.entity.Seckill -》 SeckillD-->
            <property name="typeAliasesPackage" value="seckill.entity"/>
            <!-- 扫描sql配置文件:mapper需要的xml文件 -->
            <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        </bean>
        <!-- 4: 配置扫描DAO接口包 目的:动态实现DAO接口,并注入到Spring容器中,最能节省工作量的配置-->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!-- 注入sqlSession-->
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
            <!--给出需要扫描DAO接口包 -->
            <property name="basePackage" value="seckill.dao"/>
        </bean>
    </beans>
    

    此处插曲一个快捷键ALT+ENTER: 生成实体类的Junit单元测试。

    4 DAO编写单元测试

    通过ALT+ENTER对实体类生成相应的单元测试,此处的代码:

    package seckill.dao;
    
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import seckill.entity.Seckill;
    
    import javax.annotation.Resource;
    
    import java.util.Date;
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    /**
     * Created by kason_zhang on 4/19/2017.
     */
    
    /**
     * 配置Spring与Junit整合,junit启动时加载springIOC容器
     * spring-test,junit
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    //告诉Junit spring配置文件
    @ContextConfiguration({"classpath:spring/spring-dao.xml"})
    
    public class SeckillDaoTest {
        //注入DAO实现依赖
        @Resource
        private SeckillDao seckillDao;
        @org.junit.Test
        public void reduceNumber() throws Exception {
            Date killTime = new Date();
            int i = seckillDao.reduceNumber(1000L, killTime);
            System.out.println(i);
        }
    
        @org.junit.Test
        public void queryById() throws Exception {
            long id = 1000;
            Seckill seckill = seckillDao.queryById(id);
            //Seckill{seckillId=1000, name='1000??iphone6', number=100, startTime=Sun Nov 01 00:00:00 CST 2015, endTime=Mon Nov 02 00:00:00 CST 2015, createTime=Wed Apr 19 11:29:43 CST 2017}Apr 19, 2017 5:26:57 PM
            System.out.print(seckill);
        }
    
        @org.junit.Test
        public void queryAll() throws Exception {
    
            //java没有保存形参的记录:queryAll(int offset,int limit) -> queryAll(arg0,arg1)
            List<Seckill> seckills = seckillDao.queryAll(0, 100);
            for(Seckill s : seckills){
                System.out.print(s);
            }
        }
    
    }
    
    package seckill.dao;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import seckill.entity.SuccessKilled;
    
    import javax.annotation.Resource;
    
    import static org.junit.Assert.*;
    
    /**
     * Created by kason_zhang on 4/19/2017.
     */
    /**
     * 配置Spring与Junit整合,junit启动时加载springIOC容器
     * spring-test,junit
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    //告诉Junit spring配置文件
    @ContextConfiguration({"classpath:spring/spring-dao.xml"})
    
    public class SuccessKilledDaoTest {
        @Resource
        private SuccessKilledDao successKilledDao;
        @Test
        public void insertSuccessKilled() throws Exception {
            long id = 1000;
            long phone = 13502188013L;
            int insertCount = successKilledDao.insertSuccessKilled(id,phone);
            System.out.println("insertCount = " + insertCount);
    
        }
    
        @Test
        public void queryByIdWithSeckill() throws Exception {
            long id = 1000;
            long phone = 13502188013L;
            SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(id, phone);
            System.out.println(successKilled);
            System.out.println(successKilled.getSeckill());
        }
    
    }
    

    相关文章

      网友评论

        本文标题:SSM学习一DAO层相关配置与实践

        本文链接:https://www.haomeiwen.com/subject/nhvczttx.html