20-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
 
 
- eviction:缓存回收策略(默认的是 LRU)
- 代码测试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 中非常方便的第三方分页插件。
使用步骤
- 导入相关包 pagehelper-x.x.x.jar 和 jsqlparser-0.9.5.jar
- 在 MyBatis 全局配置文件中配置分页插件<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
- 使用 PageHelper 提供的方法进行分页
- 可以使用更强大的 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>  ");
        // 2. 拼接上一页
        if(pageInfo.isHasPreviousPage()) {
            builder.append("<a href='" + path + "emps/"
                    + pageInfo.getPrePage() + "'>上一页</a>  ");
        } else {
            builder.append("上一页  ");
        }
        // 3. 拼接页码
        int[] nums = pageInfo.getNavigatepageNums();
        for(int i : nums) {
            if(i == pageInfo.getPageNum()) {
                builder.append(i+"  ");
            } else {
                builder.append("<a href='" + path
                        + "emps/"+i+"'>"+i+"</a>  ");
            }
        }
        // 4. 拼接下一页
        if(pageInfo.isHasNextPage()) {
            builder.append("<a href='" + path + "emps/"
                    + pageInfo.getNextPage()+"'></a>  ");
        } else {
            builder.append("下一页  ");
        }
        // 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>

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号