zoukankan      html  css  js  c++  java
  • 08-MyBatis(2)

    MyBatis 动态 SQL

    简介

    • 动态 SQL 是 MyBatis 强大特性之一。极大的简化我们拼装 SQL 的操作
    • 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似
    • MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作
      • if
      • choose (when,otherwise)
      • trim (where,set)
      • foreach
    • OGNL (Object Graph Navigation Language) 对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。类似于我们的 EL,SpEL 等。
      • 访问对象属性:person.name
      • 调用方法:person.getName()
      • 调用静态属性/方法:@java.lang.Math@PI,@java.util.UUID@randomUUID()
      • 调用构造方法:new cn.edu.nuist.Person('admin').name
      • 运算符:+,-,*,/,%
      • 逻辑运算符:in,not in,>,>=,<,<=,==,!=
      • 注意:xml 中特殊符号如 ",>,< 等这些都需要使用转义字符

    if & where

    <if> 用于完成简单的判断

    <!-- List<Emp> getEmpListByConditions(); -->
    <select id="getEmpListByConditions" resultType="Emp">
        SELECT eid, ename, age, sex, did FROM emp WHERE 1 = 1
        <if test="eid != null">
            AND eid = #{eid}
        </if>
        <if test="ename != null and ename != ''">
            AND ename = #{ename}
        </if>
        <if test="age != null and age != '' ">
            AND age = #{age}
        </if>
        <if test="sex == 1 or sex == 0">
            AND sex = #{sex}
        </if>
    </select>
    

    <where> 用于添加 where 关键字,并解决 SQL 语句的条件中第一个 AND 或者 OR 的问题

    <!-- List<Emp> getEmpListByConditions(); -->
    <select id="getEmpListByConditions" resultType="Emp">
        SELECT eid, ename, age, sex, did FROM emp
        <where>
            <!-- 添加 where 关键字,去掉多余的 and -->
            <if test="eid != null">
                AND eid = #{eid}
            </if>
            <if test="ename != null and ename != ''">
                AND ename = #{ename}
            </if>
            <if test="age != null and age != '' ">
                AND age = #{age}
            </if>
            <if test="sex == 1 or sex == 0">
                AND sex = #{sex}
            </if>
        </where>
    </select>
    

    Quiz:若 AND 放在条件尾部,此时如果只给 age 条件,SQL 语句末尾就会多出一个 AND

    <!-- List<Emp> getEmpListByConditions(); -->
    <select id="getEmpListByConditions" resultType="Emp">
        SELECT eid, ename, age, sex, did FROM emp
        <where>
            <!-- 添加 where 关键字,去掉多余的 and -->
            <if test="eid != null">
                eid = #{eid} AND
            </if>
            <if test="ename != null and ename != ''">
                ename = #{ename} AND
            </if>
            <if test="age != null and age != '' ">
                age = #{age} AND
            </if>
            <if test="sex == 1 or sex == 0">
                sex = #{sex}
            </if>
        </where>
    </select>
    

    测试时报错:

    Preparing: SELECT eid, ename, age, sex, did FROM emp WHERE age = ? AND
    Parameters: 40(Integer)
    

    trim

    trim 可以在条件判断完的 SQL 语句前后添加或者去掉指定的字符(可解决上述 where 尾部多一个 AND 的问题)

    • prefix:在 SQL 前添加指定的前缀
    • prefixOverrides:去掉 SQL 中指定的前缀
    • suffix:在 SQL 后添加指定的后缀
    • suffixOverrides:去掉 SQL 中指定的后缀
    <!-- List<Emp> getEmpListByConditions(); -->
    <select id="getEmpListByConditions" resultType="Emp">
        SELECT eid, ename, age, sex, did FROM emp
        <!-- 添加 where 关键字,去掉多余的 and 或者 or -->
        <trim prefix="where" suffixOverrides="and|or">
            <if test="eid != null">
                eid = #{eid} AND
            </if>
            <if test="ename != null and ename != ''">
                ename = #{ename} AND
            </if>
            <if test="age != null and age != '' ">
                age = #{age} AND
            </if>
            <if test="sex == 1 or sex == 0">
                sex = #{sex}
            </if>
        </trim>
    </select>
    

    choose(when|otherwise)

    choose 主要是用于分支判断,类似于 Java 中的 switch-case,只会满足所有分支中的一个

    <!-- void insertEmp(Emp emp); [1|0 → 男|女] -->
    <insert id="insertEmp">
        INSERT INTO emp(eid, ename, age, sex) VALUES (
            null, #{ename}, #{age},
            <choose>
                <when test="sex == 1">'男'</when>
                <when test="sex == 0">'女'</when>
                <otherwise>'不详'</otherwise>
            </choose>
        )
    </insert>
    

    set

    set 主要是用于解决修改操作中 SQL 语句中可能多出逗号的问题

    <update id="updateEmpByConditionSet">
        UPDATE emp
        <set>
            <if test="ename != null and ename != ''">
                ename = #{ename},
            </if>
            <if test="age != null and age != ''">
                age = #{age},
            </if>
            <if test="sex == 1 or sex == 0">
                sex = #{sex}
            </if>
        </set>
        WHERE eid = #{eid}
    </update>
    

    foreach

    foreach 主要用于循环迭代。

    • collection:要迭代的集合
    • item:当前从集合中迭代出的元素
    • open:循环体的开始字符
    • close:循环体的结束字符
    • separator:元素与元素之间的分隔符
    • index:迭代的是 List 集合,index 表示的当前元素的下标;迭代的 Map 集合,index 表示的当前元素的 key

    • 批量删除员工
      • 方式一
        <!-- void deleteEmps(String eids); -->
        <delete id="deleteEmps">
            DELETE FROM emp WHERE eid IN (${value})
        </delete>
        ===============================================
        Preparing: DELETE FROM emp WHERE eid IN (10, 12)
        Parameters:
        Updates: 2
        
      • 方式二
        <!-- void deleteEmpsByList(List<Integer> eids); -->
        <delete id="deleteEmpsByList">
            DELETE FROM emp WHERE eid IN
            <foreach collection="list" item="eid" separator="," open="(" close=")">
                #{eid}
            </foreach>
        </delete>
        =============================================================
        Preparing: DELETE FROM emp WHERE eid IN ( ? , ? )
        Parameters: 9(Integer), 6(Integer)
        Updates: 2
        
    • 批量插入
      <!-- void batchInsertEmps(@Param("emps")Emp[] emps); -->
      <insert id="batchInsertEmps">
          INSERT INTO emp(eid, ename, age, sex) VALUES
          <foreach collection="emps" item="emp" separator=",">
              (null, #{emp.ename}, #{emp.age}, #{emp.sex})
          </foreach>
      </insert>
      
    • 批量修改
      <!--
      把每条数据修改为相同的内容
          UPDATE emp SET ... WHERE eid IN (1, 2, 3);
          UPDATE emp SET ... WHERE eid=1 OR eid=2 OR eid=3;
      把每条数据修改为相对应内容 (一次执行多条 SQL 语句要求 jdbc.url 后有参数 allowMultiQueries)
          UPDATE emp SET ... WHERE eid=1;
          UPDATE emp SET ... WHERE eid=2;
          UPDATE emp SET ... WHERE eid=3;
       -->
      <!-- void batchUpdateEmps(@Param("emps")Emp[] emps); -->
      <!-- jdbc.url=jdbc:mysql:///test?allowMultiQueries=true -->
      <update id="batchUpdateEmps">
          <foreach collection="emps" item="emp">
              UPDATE emp SET ename=#{emp.ename}, age=#{emp.age}
                  , sex=#{emp.sex} WHERE eid=#{emp.eid};
          </foreach>
      </update>
      

    sql

    sql 标签是用于抽取可重用的 sql 片段,将相同的,使用频繁的 SQL 片段抽取出来,单独定义,方便多次引用。

    • 抽取 SQL
      <sql id="empColumns">SELECT eid, ename, age, sex FROM emp</sql>
      
    • 引用 SQL
      <include refid="empColumns"/>
      

    MyBatis 缓存机制

    缓存机制简介

    • MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率
    • MyBatis系统中默认定义了两级缓存:一级缓存、二级缓存
    • 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启
    • 二级缓存需要手动开启和配置,它是基于 namespace 级别的缓存
    • 为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存

    一级缓存

    一级缓存的使用

    • 一级缓存(local cache),即本地缓存,作用域默认为 SqlSession。当 Session flush 或 close 后,该 Session 中的所有 Cache 将被清空
    • 本地缓存不能被关闭,但可以调用 clearCache() 来清空本地缓存,或者改变缓存的作用域
    • 在 MyBatis3.1 之后,可以配置本地缓存的作用域。在 mybatis.xml 中配置
    • 一级缓存的工作机制
      • 同一次会话期间只要查询过的数据都会保存在当前 SqlSession 的一个 Map 中
      • key:hashCode + 查询的 SqlId + 编写的 sql 查询语句 + 参数
    @Test
    public void testFirstCache() throws IOException {
        SqlSession session = getSqlSessionFactory().openSession(true);
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        Emp emp1 = mapper.getEmpByEid("3");
        Emp emp2 = mapper.getEmpByEid("3");
        System.out.println(emp1);
        System.out.println("+++++++++++++++++++++");
        System.out.println(emp2);
    }
    
    ======================= 打印控制台 =======================
    Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
    Parameters: 3(String)
    Total: 1
    Emp [eid=3, ename=root, age=30, sex=0]
    +++++++++++++++++++++
    Emp [eid=3, ename=root, age=30, sex=0]
    

    一级缓存失效的几种情况

    • 不同的 SqlSession 对应不同的一级缓存
    • 同一个 SqlSession 但是查询条件不同
    • 同一个 SqlSession 两次查询期间执行了任何一次增删改操作(无论成功与否)
    • 同一个 SqlSession 两次查询期间手动清空了缓存
    @Test
    public void testFirstCache() throws IOException {
        SqlSession session = getSqlSessionFactory().openSession(true);
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        Emp emp1 = mapper.getEmpByEid("13");
        System.out.println(emp1);
        System.out.println("+++++++++++++++++++++");
        mapper.deleteEmpsByString("3"); // 不存在该记录
        System.out.println("+++++++++++++++++++++");
        Emp emp2 = mapper.getEmpByEid("13");
        System.out.println(emp2);
    }
    ======================= 打印控制台 =======================
    Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
    Parameters: 13(String)
    Total: 1
    Emp [eid=13, ename=AAA, age=22, sex=0]
    +++++++++++++++++++++
    Preparing: DELETE FROM emp WHERE eid IN (3)
    Parameters:
    Updates: 0
    +++++++++++++++++++++
    Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
    Parameters: 13(String)
    Total: 1
    Emp [eid=13, ename=AAA, age=22, sex=0]
    

    二级缓存

    二级缓存的使用

    • 简述
      • 二级缓存(second level cache),全局作用域缓存
      • 二级缓存默认不开启,需要手动配置
      • MyBatis 提供二级缓存的接口以及实现,缓存实现要求 POJO 实现 Serializable 接口
      • 一级缓存是 SqlSession 级别的,二级缓存是映射文件级别的。二级缓存在 SqlSession 关闭或提交之后才会生效
    • 二级缓存使用的步骤
      • 全局配置文件中开启二级缓存 <setting name="cacheEnabled" value="true"/>
      • 需要使用二级缓存的映射文件处使用 cache 配置缓存 <cache />
      • 注意:POJO 需要实现 Serializable<I>
    • 二级缓存相关的属性
      • eviction:缓存回收策略(默认的是 LRU)
        • LRU – 最近最少使用的:移除最长时间不被使用的对象
        • FIFO – 先进先出:按对象进入缓存的顺序来移除它们
        • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象
        • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
      • flushInterval:刷新间隔,单位毫秒。默认情况不设置,也就是没有刷新间隔,代表永不刷新,缓存仅在调用语句时刷新
      • size:引用数目,正整数。代表缓存最多可以存储多少个对象,太大容易导致内存溢出
      • readOnly:只读
        • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势
        • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false
    • 代码测试1
      @Test
      public void testSecondCache() throws IOException {
          SqlSession session = getSqlSessionFactory().openSession(true);
          EmpMapper mapper1 = session.getMapper(EmpMapper.class);
          Emp emp1 = mapper1.getEmpByEid("13");
          System.out.println(emp1);
          System.out.println("++++++++++++++++++++++++");
          EmpMapper mapper2 = session.getMapper(EmpMapper.class);
          Emp emp2 = mapper2.getEmpByEid("13");
          System.out.println(emp2);
      }
      ======================= 打印控制台 =======================
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.0 ← 命中率
      Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
      Parameters: 13(String)
      Total: 1
      Emp [eid=13, ename=AAA, age=22, sex=0]
      ++++++++++++++++++++++++
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.0 → 二级缓存未生效
      Emp [eid=13, ename=AAA, age=22, sex=0]
      
    • 代码测试2
      @Test
      public void testSecondCache() throws IOException {
          SqlSession session = getSqlSessionFactory().openSession(true);
          EmpMapper mapper1 = session.getMapper(EmpMapper.class);
          Emp emp1 = mapper1.getEmpByEid("13");
          System.out.println(emp1);
          EmpMapper mapper2 = session.getMapper(EmpMapper.class);
          Emp emp2 = mapper2.getEmpByEid("13");
          System.out.println(emp2);
          // >>> 二级缓存在 SqlSession 关闭或提交之后才会生效 <<<
          session.commit();
          EmpMapper mapper3 = session.getMapper(EmpMapper.class);
          Emp emp3 = mapper3.getEmpByEid("13");
          System.out.println(emp3);
          session.commit();
          EmpMapper mapper4 = session.getMapper(EmpMapper.class);
          Emp emp4 = mapper4.getEmpByEid("13");
          System.out.println(emp4);
      }
      ======================= 打印控制台 =======================
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.0
      Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
      Parameters: 13(String)
      Total: 1
      Emp [eid=13, ename=AAA, age=22, sex=0]
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.0
      Emp [eid=13, ename=AAA, age=22, sex=0]
      put added 0 on heap
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.3333333333333333 [1/3]
      Emp [eid=13, ename=AAA, age=22, sex=0]
      Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.5 [2/4]
      Emp [eid=13, ename=AAA, age=22, sex=0]
      

    缓存的相关配置

    • 全局 setting 的 cacheEnable:配置二级缓存的开关,一级缓存一直是打开的
    • <select> 标签的 useCache 属性:配置这个 select 是否使用二级缓存(一级缓存是一直使用的)
    • sqlSession.clearCache():只是用来清除一级缓存
    • SQL 标签的 flushCache 属性:
      • 增删改默认 flushCache=true;查询默认 flushCache=false
      • 增删改 SQL 执行以后,会同时清空一级和二级缓存
        @Test
        public void testSecondCache() throws IOException {
            SqlSession session = getSqlSessionFactory().openSession(true);
            EmpMapper mapper1 = session.getMapper(EmpMapper.class);
            Emp emp1 = mapper1.getEmpByEid("13");
            System.out.println(emp1);
            session.commit();
            System.out.println("++++++++++++++++");
            EmpMapper mapper2 = session.getMapper(EmpMapper.class);
            Emp emp2 = mapper2.getEmpByEid("13");
            System.out.println(emp2);
            System.out.println("++++++++++++++++");
            mapper2.deleteEmpsByString("3"); // 删除操作
            System.out.println("++++++++++++++++");
            EmpMapper mapper3 = session.getMapper(EmpMapper.class);
            Emp emp3 = mapper3.getEmpByEid("13");
            System.out.println(emp3);
        }
        ======================= 打印控制台 =======================
        Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.0
        Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
        Parameters: 13(String)
        Total: 1
        Emp [eid=13, ename=AAA, age=22, sex=0]
        put added 0 on heap
        ++++++++++++++++
        Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.5
        Emp [eid=13, ename=AAA, age=22, sex=0]
        ++++++++++++++++
        fault removed 0 from heap
        fault added 0 on disk
        Preparing: DELETE FROM emp WHERE eid IN (3)
        Parameters:
        Updates: 0
        ++++++++++++++++
        Cache Hit Ratio [cn.edu.nuist.mapper.EmpMapper]: 0.6666666666666666
        Preparing: SELECT eid, ename, age, sex FROM emp WHERE eid=?
        Parameters: 13(String)
        Total: 1
        Emp [eid=13, ename=AAA, age=22, sex=0]
        

    整合第三方缓存

    • 为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存
    • EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider
    • 整合 EhCache 缓存的步骤
      • 导入 ehcache 包,以及整合包,日志包:ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar、slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
      • 编写 ehcache.xml 配置文件
        <?xml version="1.0" encoding="UTF-8"?>
        <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
        <!-- 磁盘保存路径 -->
        <diskStore path="D:ehcache" />
        <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        </defaultCache>
        </ehcache>
        
      • 在映射文件中配置 cache 标签:<cache type="org.mybatis.caches.ehcache.EhcacheCache" />

    PageHelper 分页插件

    PageHelper 是 MyBatis 中非常方便的第三方分页插件。

    使用步骤

    1. 导入相关包 pagehelper-x.x.x.jar 和 jsqlparser-0.9.5.jar
    2. 在 MyBatis 全局配置文件中配置分页插件
      <plugins>
          <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
      </plugins>
      
    3. 使用 PageHelper 提供的方法进行分页
    4. 可以使用更强大的 PageInfo 封装返回结果

    Page 对象的使用

    在查询之前通过 PageHelper.startPage(pageNum, pageSize) 设置分页信息,该方法返回 Page 对象。

    @Test
    public void testPageHelper()  throws Exception{
        SqlSessionFactory ssf = getSqlSessionFactory();
        SqlSession session = ssf.openSession();
        try {
            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
            //设置分页信息
            Page<Object> page = PageHelper.startPage(9, 1);
            List<Employee> emps = mapper.getAllEmps();
            for (Employee employee : emps) {
                System.out.println(employee);
            }
            System.out.println("====== 获取分页相关的信息 ======");
            System.out.println("当前页: " + page.getPageNum());
            System.out.println("总页码: " + page.getPages());
            System.out.println("总条数: " + page.getTotal());
            System.out.println("每页显示的条数: " + page.getPageSize());
        } finally {
            session.close();
        }
    }
    

    PageInfo 对象的使用

    在查询完数据后,使用 PageInfo 对象封装查询结果,可以获取更详细的分页信息以及可以完成分页逻辑。

    PageUtil:

    // 首页 上一页 1 2 3 4 5 下一页 尾页
    public class PageUtil {
        public static String getPageInfo(PageInfo<Emp> pageInfo) {
            String path = "/mybatis/";
            StringBuilder builder = new StringBuilder();
            // 1. 拼接首页
            builder.append("<a href='" + path + "emps/1'>首页</a>&nbsp;&nbsp;");
            // 2. 拼接上一页
            if(pageInfo.isHasPreviousPage()) {
                builder.append("<a href='" + path + "emps/"
                        + pageInfo.getPrePage() + "'>上一页</a>&nbsp;&nbsp;");
            } else {
                builder.append("上一页&nbsp;&nbsp;");
            }
            // 3. 拼接页码
            int[] nums = pageInfo.getNavigatepageNums();
            for(int i : nums) {
                if(i == pageInfo.getPageNum()) {
                    builder.append(i+"&nbsp;&nbsp;");
                } else {
                    builder.append("<a href='" + path
                            + "emps/"+i+"'>"+i+"</a>&nbsp;&nbsp;");
                }
            }
            // 4. 拼接下一页
            if(pageInfo.isHasNextPage()) {
                builder.append("<a href='" + path + "emps/"
                        + pageInfo.getNextPage()+"'></a>&nbsp;&nbsp;");
            } else {
                builder.append("下一页&nbsp;&nbsp;");
            }
            // 5. 拼接尾页
            builder.append("<a href='" + path + "emps/"
                        + pageInfo.getPages() + "'>尾页</a>");
    
            return builder.toString();
            }
        }
    

    SSM 整合

    整合步骤

    导入 jar 包

    • Spring
    • SpringMVC
    • MyBatis
    • 第三方支持:log4j,pageHelper,AspectJ,Jackson,Jstl

    搭建 SpringMVC

    • web.xml
      • DispatcherServlet
      • HiddenHttpMethodFilter
      • CharacterEncodingFilter
    • springMVC.xml
      • 扫描控制层组件
      • 视图解析器
      • DefaultServlet
      • MVC Driver
      • 可选:MultipartResolver(文件解析器),拦截器

    整合 SpringMVC 和 Spring

    • web.xml
      • ContextLoaderListener
      • context-param
    • spring.xml
      • 扫描组件(排除控制层)
      • 事务管理器

    搭建 MyBatis

    • 核心配置文件
    • mapper 接口和 mapper 映射文件

    Spring 整合 MyBatis

    • spring.xml
      • properties 文件的引入
      • DataSource 数据源的配置
      • 事务管理器
      • 开启事务驱动
      • SqlSessionFactoryBean(管理 SqlSession)
      • MapperScannerConfigurer
    • 不同 MyBatis 版本整合 Spring 时使用的适配包:

    配置文件

    web.xml

    <!-- 配置编码过滤器 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- REST 请求方式处理 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- SpringMVC 核心控制器 DispatcherServlet -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- 配置 Spring 监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- 自定义 Spring 配置文件的位置和名称 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml</param-value>
    </context-param>
    

    spring.xml

    <!-- 扫描组件 -->
    <context:component-scan base-package="cn.edu.nuist.ssm">
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
    <!-- 引入资源文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!-- 数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 声明事务管理器 -->
    <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 开启事务注解驱动 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <!-- 管理 MyBatis 操作数据库的会话对象 SqlSession -->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 设置 MyBatis 核心配置文件的路径 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 设置数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- 设置类型别名 -->
        <property name="typeAliasesPackage" value="cn.edu.nuist.ssm.bean"></property>
        <!-- 设置映射文件的路径 -->
        <property name="mapperLocations" value="classpath:cn/edu/nuist/ssm/mapper/*.xml"></property>
    </bean>
    
    <!-- 在所设置的包下,将所有的接口生成动态代理实现类对象,并由 Spring 容器管理 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.edu.nuist.ssm.mapper"></property>
    </bean>
    

    springMVC.xml

    <!-- 扫描控制层组件 -->
    <context:component-scan base-package="cn.edu.nuist.ssm.controller"></context:component-scan>
    
    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    
    <!-- 默认Servlet -->
    <mvc:default-servlet-handler/>
    
    <!-- MVC 驱动 -->
    <mvc:annotation-driven />
    

    mybatis-config.xml

    <configuration>
        <settings>
            <!-- 将下划线映射成驼峰, 例如:user_name → userName -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <!-- 开启延迟加载 -->
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/>
            <!-- 是否开启二级缓存 -->
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
        <plugins>
            <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
        </plugins>
    </configuration>
    
  • 相关阅读:
    加入页面切换动画, 避免冷启动
    Spark Shuffle模块——Suffle Read过程分析
    java使用线程请求訪问每次间隔10分钟连续5次,之后停止请求
    二叉排序树(BST)构造与应用
    L贪心基础
    leetcode笔记:Ugly Number II
    Android API Guides---Layouts
    红外目标图像中阈值切割方法的比較与研究
    IOS开发证书变成“此证书的签发者无效”解决方法
    Web前端开发规范收集
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/13672232.html
Copyright © 2011-2022 走看看