之前Spring和SpringMVC已经整合成功了,现在开始整合MyBatis。
先在数据库中创建emp表:

DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `id` varchar(64) NOT NULL,
  `name` varchar(100) NOT NULL,
  `age` int(11) DEFAULT NULL,
  `gender` int(11) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL,
  `hiredate` datetime DEFAULT NULL,
  `job` varchar(10) DEFAULT NULL,
  `hobbies` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在之前的spring-context.xml开始添加配置
1、配置注解扫描,扫描service包下的注解,主要是为了之后可以将@Service注解的类注入到Controller层进行使用

    <!-- 开启注解扫描 start -->
    <context:annotation-config />   
    <context:component-scan base-package="com.sdusz.framework.ssm" use-default-filters="false">
        <context:include-filter type="regex" expression="com.sdusz.framework.ssm.service*.*" />
    </context:component-scan>
    <!-- 开启注解扫描 end -->

2、配置读取properties的bean,读取到的所有properties配置文件中的所有键值对,之后要用到其中的值只需要${key}即可使用

    <!-- 加载properties配置文件 start -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:config/jdbc.properties</value>
            </list>
        </property>
        <!-- <property name="ignoreUnresolvablePlaceholders" value="true" /> -->
    </bean>
    <!-- 加载properties配置文件 end -->

3、配置数据源:这里我选择使用阿里的druid数据源,第一安全性高,第二异常的处理比其他数据源更为强大,第三由于阿里公司的业务偏向大数据,数据源设计自然也吸取了大数据高并发的一些理念进行设计,而且经过前人实践证明,执行效率确实是目前主流数据源中最高的。

<!-- 配置druid数据源 start -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="filters" value="${jdbc.filters}" />
        <property name="maxActive" value="${jdbc.maxActive}" />
        <property name="initialSize" value="${jdbc.initialSize}" />
        <property name="maxWait" value="${jdbc.maxWait}" />
        <property name="minIdle" value="${jdbc.minIdle}" />
        <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
        <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}" />
        <property name="validationQuery" value="${jdbc.validationQuery}" />
        <property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
        <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
        <property name="testOnReturn" value="${jdbc.testOnReturn}" />
        <property name="poolPreparedStatements" value="${jdbc.poolPreparedStatements}" />
        <property name="maxOpenPreparedStatements" value="${jdbc.maxOpenPreparedStatements}" />
        <property name="removeAbandoned" value="${jdbc.removeAbandoned}" />
        <property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}" />
        <property name="logAbandoned" value="${jdbc.logAbandoned}" />
    </bean>
    <!-- 配置druid数据源 end -->

上面的bean中property对应的值,就是从jdbc.properties配置文件中读取的,jdbc.properties配置文件的内容如下:

####druid数据源配置
#链接字符串
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
#数据库驱动类名
jdbc.driverClassName=com.mysql.jdbc.Driver
#用户名
jdbc.username=root 
#密码
jdbc.password=root
#属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
jdbc.filters=stat 
#最大连接池数量
jdbc.maxActive=20 
#初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
jdbc.initialSize=10
#获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配useUnfairLock属性为true使用非公平锁。
jdbc.maxWait=60000 
#最小连接池数量
jdbc.minIdle=10 
#有两个含义:1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
jdbc.timeBetweenEvictionRunsMillis=60000 
#一个连接在池中最小生存的时间,单位是毫秒
jdbc.minEvictableIdleTimeMillis=300000 
#用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
jdbc.validationQuery=SELECT 'x' 
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
jdbc.testWhileIdle=true 
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
jdbc.testOnBorrow=false 
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
jdbc.testOnReturn=false 
#在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
jdbc.maxOpenPreparedStatements=20 
#是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
jdbc.poolPreparedStatements=true 
#打开removeAbandoned功能
jdbc.removeAbandoned=true 
#1800秒,也就是30分钟
jdbc.removeAbandonedTimeout=1800 
#关闭abanded连接时输出错误日志
jdbc.logAbandoned=true

4、配置MyBatis的SqlSssionFactory,mapperLocations配置为扫描src/main/mybatis目录下的所有.xml文件,就是所有的MyBatis的mapper.xml文件,另外设置mybatis的全局配置文件路径,这个可以不用配置,这样就使用默认配置。

    <!-- 配置sqlSessionFactory start-->
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <!-- 自动扫描mapper文件 -->  
        <property name="mapperLocations" value="classpath:mybatis/*.xml"></property>  
        <!-- mybatis全局配置文件 -->
        <property name="configLocation" value="classpath:config/mybatis-config.xml"></property>
     </bean>  
    <!-- 配置sqlSessionFactory end-->

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>
        <!-- 配置全局性 cache 的 ( 开 / 关) default:true -->
        <setting name="cacheEnabled" value="false"/>
        <!-- 是否使用 懒加载 关联对象同 hibernate中的延迟加载 一样default:true -->
        <!-- <setting name="lazyLoadingEnabled" value="true"/> -->
        <!-- [当对象使用延迟加载时 属性的加载取决于能被引用到的那些延迟属性,否则,按需加载(需要的是时候才去加载)] -->
        <setting name="aggressiveLazyLoading" value="true"/>
        <!-- 是否允许单条sql 返回多个数据集(取决于驱动的兼容性) default:true -->
        <setting name="multipleResultSetsEnabled" value="true"/>
        <!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true-->
        <setting name="useColumnLabel" value="true"/>
        <!--允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。default:false-->
        <setting name="useGeneratedKeys" value="false"/>
        <!--指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分FULL:全部-->
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <!-- 这是默认的执行类型 
            SIMPLE :简单  
            REUSE:执行器可能重复使用prepared statements 语句 
            BATCH:执行器可以重复执行语句和批量更新
        -->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!-- 设置驱动等待数据响应的超时数默认没有设置-->
        <setting name="defaultStatementTimeout" value="25000"/>
        <!--是否启用 行内嵌套语句defaut:false-->
        <setting name="safeRowBoundsEnabled" value="false"/>
        <!-- [是否 启用数据中 A_column 自动映射 到 java类中驼峰命名的属性 default:fasle] -->
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <!-- 设置本地缓存范围 session:就会有数据的共享statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
        <setting name="localCacheScope" value="SESSION"/>
        <!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER -->
        <setting name="jdbcTypeForNull" value="NULL"/>
        <!-- 设置触发延迟加载的方法-->
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings> 
</configuration>

5、配置扫描dao接口所在的包

    <!-- 扫描Dao接口所在的包名 start -->  
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="com.sdusz.framework.ssm.mapper" />  
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
    </bean>  
    <!-- 扫描Dao接口所在的包名 end -->

6、配置JdbcTemplate,本来集成了mybatis,为何还要jdbcTemplate呢?原因是mybatis的批量处理效率不高,而且不同数据库,写法也略有差异,使用更接近底层jdbc的jdbcTemplate进行批量操作,可以提升性能。

    <!-- jdbcTemplate start -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"/>
    </bean>
    <!-- jdbcTemplate end -->

7、配置数据源事务切面,进行事务管理,我将事务的回滚配置在service层,对于异常,进行回滚,如果有异常,不要捕获,直接网上抛,到时用一个统一的拦截器进行处理即可,对于需要用事务进行控制的方法,方法的命名一定要以下面事务切面中给出的前缀命名,当然,也可自己添加其它的。

<!-- 数据源事务管理器start -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 数据源事务管理器end -->

    <!-- 事务切面 start-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="count*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" read-only="true" />
            <tx:method name="search*" propagation="REQUIRED" read-only="true" />
            <tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="modify*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="edit*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <!-- 批量操作最好用jdbcTemplate -->
            <tx:method name="batch*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
        </tx:attributes>
    </tx:advice>
    <!-- 事务切面 end -->

    <!-- 事务aop切入点 start-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.sdusz.framework.ssm.service.*.*(..)) " />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
    </aop:config>
    <!-- 事务aop切入点 end-->

下面进行测试

1、在com.sdusz.framework.ssm.entity添加反向生成的Emp.java类,对应数据库中的EMP表

package com.sdusz.framework.ssm.entity;

import java.io.Serializable;
import java.util.Date;

import com.alibaba.fastjson.JSON;

/**
 * 文件名称: com.sdusz.framework.ssm.entity.Emp.java
 * 初始作者: shenmengqi
 * 创建日期: 2016年3月18日
 * 功能说明: 测试实体-员工实体类 
 * =================================================
 * 修改记录:
 * 修改作者 日期 修改内容
 * ================================================
 * Copyright (c) 2010-2011 .All rights reserved.
 */
public class Emp implements Serializable {

    /**
     * 序列化版本号
     */
    private static final long   serialVersionUID    = 1L;

    /**
     * 实体对应的数据库表名
     */
    public static final String  TABLE_NAME          = "emp";

    /**
     * id
     */
    private String              id;

    /**
     * 姓名
     */
    private String              name;

    /**
     * 年龄
     */
    private Integer             age;

    /**
     * 性别
     */
    private Integer             gender;

    /**
     * 生日
     */
    private Date                birthday;

    /**
     * 入职日期
     */
    private Date                hiredate;
    /**
     * 工作
     */
    private String              job;

    /**
     * 爱好
     */
    private String              hobbies;

    /**
     * 方法描述: 获取年龄
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:31:17
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         Integer 年龄
     */
    public Integer getAge() {

        return age;
    }

    /**
     * 方法描述: 获取生日
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:31:40
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         Date 生日
     */
    public Date getBirthday() {

        return birthday;
    }

    /**
     * 方法描述: 获取性别
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:31:57
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         Integer 性别
     */
    public Integer getGender() {

        return gender;
    }

    /**
     * 方法描述: 获取入职日期
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:32:17
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         Date 入职日期
     */
    public Date getHiredate() {

        return hiredate;
    }

    /**
     * 方法描述: 获取爱好
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:32:37
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         String 爱好
     */
    public String getHobbies() {

        return hobbies;
    }

    /**
     * 方法描述: 获取id
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:33:02
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         String id
     */
    public String getId() {

        return id;
    }

    /**
     * 方法描述: 获取工作
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:33:20
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         String 工作
     */
    public String getJob() {

        return job;
    }

    /**
     * 方法描述: 获取姓名
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:33:37
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return
     *         String 姓名
     */
    public String getName() {

        return name;
    }

    /**
     * 方法描述: 设置年龄
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:33:54
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param age
     *            年龄
     */
    public void setAge(Integer age) {

        this.age = age;
    }

    /**
     * 方法描述: 设置生日
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:34:09
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param birthday
     *            生日
     */
    public void setBirthday(Date birthday) {

        this.birthday = birthday;
    }

    /**
     * 方法描述: 设置性别
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:34:30
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param gender
     *            性别
     */
    public void setGender(Integer gender) {

        this.gender = gender;
    }

    /**
     * 方法描述: 设置入职日期
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:34:56
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param hiredate
     *            入职日期
     */
    public void setHiredate(Date hiredate) {

        this.hiredate = hiredate;
    }

    /**
     * 方法描述: 设置爱好
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:35:16
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param hobbies
     *            爱好
     */
    public void setHobbies(String hobbies) {

        this.hobbies = hobbies;
    }

    /**
     * 方法描述: 设置id
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:35:37
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param id
     *            id
     */
    public void setId(String id) {

        this.id = id;
    }

    /**
     * 方法描述: 设置工作
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:35:53
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param job
     *            工作
     */
    public void setJob(String job) {

        this.job = job;
    }

    /**
     * 方法描述: 设置姓名
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:36:10
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param name
     *            姓名
     */
    public void setName(String name) {

        this.name = name;
    }

    /**
     * 方法描述: 重写toString()方法
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月22日-下午2:14:07
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     */
    @Override
    public String toString() {

        return JSON.toJSONString(this);
    }

}

2、com.sdusz.framework.ssm.mapper添加反向生成的EmpMapper.java类,删去其中的默认方法,添加自己需要的方法

package com.sdusz.framework.ssm.mapper;

import org.apache.ibatis.annotations.Param;

import com.sdusz.framework.ssm.entity.Emp;

/**
 * 文件名称: com.sdusz.framework.ssm.mapper.EmpMapper.java
 * 初始作者: shenmengqi
 * 创建日期: 2016年3月18日
 * 功能说明: 员工mapper 
 * =================================================
 * 修改记录:
 * 修改作者 日期 修改内容
 * ================================================
 * Copyright (c) 2010-2011 .All rights reserved.
 */
public interface EmpMapper {

    /**
     * 方法描述: 通过id获取员工信息
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月17日-下午1:45:04
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param id
     *            主键
     * @return
     *         Emp 员工实体
     */
    Emp selectEmpById(@Param("id") String id);
}

3、在src/main/resources下的mybatis目录下添加反向生成的EmpMapper.xml文件,删除其中的无用内容,添加自己的语句,对应每个语句的id即为EmpMapper.java中每个方法的方法名

<?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 -->
<mapper namespace="com.sdusz.framework.ssm.mapper.EmpMapper" >
    <!-- 通过id获取员工信息-->
    <select id="selectEmpById" parameterType="java.lang.String" resultType="com.sdusz.framework.ssm.entity.Emp">
        select * from emp where id=#{id,jdbcType=BIGINT}
    </select>
</mapper>

4、com.sdusz.framework.ssm.service添加EmpService.java接口

package com.sdusz.framework.ssm.service;

import com.sdusz.framework.ssm.entity.Emp;

/**
 * 文件名称: com.sdusz.framework.ssm.service.EmpService.java
 * 初始作者: shenmengqi
 * 创建日期: 2016年3月18日
 * 功能说明: 员工service 
 * =================================================
 * 修改记录:
 * 修改作者 日期 修改内容
 * ================================================
 * Copyright (c) 2010-2011 .All rights reserved.
 */
public interface EmpService {

    /**
     * 方法描述: 批量添加员工信息,用jdbc,另一方面为了测试事务的有效性
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:49:09
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return int
     *         插入成功的数量
     * @throws Exception
     *             异常
     */
    int batchAddEmp() throws Exception;

    /**
     * 方法描述: 通过id获取员工信息
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:49:55
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param id
     *            员工id
     * @return
     *         Emp 员工实体
     */
    Emp getEmpById(String id);
}

5、com.sdusz.framework.ssm.serviceImpl添加EmpServiceImpl.java类,实现EmpService接口,对于JdbcTemplate还有EmpMapper直接使用@Autowired进行注入,第二个方法直接通过id获取员工信息,第一个方法使用JdbcTemplate批量插入员工信息(这里我没用批量插入的api,为了观察更清晰,用循环进行插入,看某一条出错,其余是否会回滚),顺便可以测试异常事务切面异常情况是否会进行回滚

package com.sdusz.framework.ssm.serviceImpl;
import java.util.Date;
import java.util.Random;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import com.sdusz.framework.ssm.entity.Emp;
import com.sdusz.framework.ssm.mapper.EmpMapper;
import com.sdusz.framework.ssm.service.EmpService;
import com.sdusz.framework.ssm.util.UUIDUtils;

/**
 * 文件名称: com.sdusz.framework.ssm.serviceImpl.EmpServiceImpl.java
 * 初始作者: shenmengqi
 * 创建日期: 2016年3月18日
 * 功能说明: 员工service实现类
 * =================================================
 * 修改记录:
 * 修改作者 日期 修改内容
 * ================================================
 * Copyright (c) 2010-2011 .All rights reserved.
 */
public class EmpServiceImpl implements EmpService {

    /**
     * log4j日志对象
     */
    private static final Logger log = Logger.getLogger(EmpServiceImpl.class);

    /**
     * 员工mapper
     */
    @Autowired
    private EmpMapper           empMapper;

    /**
     * jdbcTemplate
     */
    @Autowired
    private JdbcTemplate        jdbcTemplate;

    /**
     * 方法描述: 用jdbcTemplate循环插入员工信息,一方面测试jdbcTemplate,另一方面测试事务有效性
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月17日-下午2:03:11
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @throws Exception
     *             异常对象
     */

    @Override
    public int batchAddEmp() throws Exception {

        int r = 0;
        for (int i = 0; i < new Random().nextInt(5); i++) {
            // log.info("开始插入第" + (i + 1) + "条");
            Emp e = new Emp();
            e.setId(UUIDUtils.get32UUID());
            e.setName("name" + i);
            e.setJob("job" + i);
            e.setHobbies("hobbies" + i);
            e.setGender(new Random().nextInt(1));
            e.setAge(new Random().nextInt(30));
            e.setBirthday(new Date());
            e.setHiredate(new Date());
            // if (i == 7) {
            // log.error("出错了,回滚!");
            // throw new Exception("出错了!");
            // }
            int rr = jdbcTemplate.update("insert into emp values(?,?,?,?,?,?,?,?)", new Object[] {
                    e.getId(),
                    e.getName(),
                    e.getAge(),
                    e.getGender(),
                    e.getBirthday(),
                    e.getHiredate(),
                    e.getJob(),
                    e.getHobbies()
            });
            if (rr == 1) {
                r++;
            }
            // log.info("第" + (i + 1) + "条插入成功");
        }
        return r;
    }

    /**
     * 方法描述: 通过id获取员工信息,有缓存
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:51:55
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     */
    @Override
    @Cacheable(value = "empCache", key = "#id+'~cache'", condition = "#id=='1406'")
    public Emp getEmpById(String id) {

        System.out.println("调用了getEmpById() 方法");
        return empMapper.selectEmpById(id);
    }

}

6、com.sdusz.framework.ssm.controller中添加EmpController.java类,EmpService使用@Resource进行注入,一般Controller层只是一个负责转发的层,所以,业务逻辑能在Service层处理就尽量在Service层处理,每一层必要的日志记录也是需要的。Controller遇到异常也不要捕获,向上抛出由统一的异常拦截器进行处理。

package com.sdusz.framework.ssm.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.sdusz.framework.ssm.entity.Emp;
import com.sdusz.framework.ssm.service.EmpService;
/**
 * 文件名称: com.sdusz.framework.ssm.controller.EmpController.java
 * 初始作者: shenmengqi
 * 创建日期: 2016年3月18日
 * 功能说明: 测试类,员工信息控制器 
 * =================================================
 * 修改记录:
 * 修改作者 日期 修改内容
 * ================================================
 * Copyright (c) 2010-2011 .All rights reserved.
 */
@Controller
@RequestMapping("emp")
public class EmpController {

    /**
     * 员工信息service
     */
    @Resource
    private EmpService  empService;

    /**
     * 方法描述: 批量添加员工信息
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:18:35
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @return int
     *         插入成功的记录数
     * @throws Exception
     *             异常
     */
    @RequestMapping("/addEmps")
    @ResponseBody
    public int addEmps() throws Exception {

        return empService.batchAddEmp();
    }

    /**
     * 方法描述: 通过id获取员工信息
     * 初始作者: shenmengqi
     * 创建日期: 2016年3月18日-上午9:20:10
     * 开始版本: 2.0.0
     * =================================================
     * 修改记录:
     * 修改作者 日期 修改内容
     * ================================================
     *
     * @param id
     *            员工id
     * @return
     *         Emp 员工实体
     */
    @RequestMapping("/getEmpById")
    @ResponseBody
    public Emp getEmpById(@RequestParam String id) {

        return empService.getEmpById(id);
    }
}

7、依次访问上面两个接口
http://ip:port/工程名/interfaces/emp/addEmps
先访问,如果批量插入成功返回影响的行数则表示jdbcTemplate可用
修改service实现类代码,制造异常,再测试,看是否回滚成功
http://ip:port/工程名/interfaces/emp/getEmpById?id=1406
直接返回员工信息json对象,则表示成功

至此就完成了一个简单Spring+SpringMVC+MyBatis框架的搭建,其实在真正的企业级开发中,做了这些是远远不够的,接下来我还要在这个框架中融入其他的东西!