原文再续,书接上回。上一次我们已经创建好了tbl_emp和tbl_dept两张表,接下来我们会用mybatis的逆向工程把这两张表对应的Mapper及bean生成出来。其实mybatis官网上关于怎么使用mybatis generator写的非常清楚,但是为了博客的连续性,我还是把步骤都写一写吧。
首先,我们在ssm_crud项目的根目录下生成mbg.xml,里边是generator的各种配置,官网上有模板,我下载下来之后修改了一些必要的地方,老规矩,配置含义什么的都写到注释里了,mbg.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 让生成的文件不带有巨多的注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm_crud"
userId="root"
password="413531">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- javabean生成的位置 -->
<javaModelGenerator targetPackage="com.sunsy.crud.bean" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 指定sql映射文件生成的位置 -->
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 指定dao接口生成的位置,mapper接口 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.sunsy.crud.dao" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- table指定每个表的生成策略 -->
<table tableName="tbl_emp" domainObjectName="Employee"></table>
<table tableName="tbl_dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
接下来在我们自己的com.sunsy.crud.test包下写一个MBGTest.java类,如下(也是官网上抄的,就把上边那个xml地址改了一下):
package com.sunsy.crud.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class MBGTest {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
运行上边的MBGTest.java即可发现mybatis已经自动给我们生成了如下几个文件:
第一次用这玩意的时候我都震惊了。。方便的一。。当然,里边有些地方需要我们自己改动,咱们一个一个来吧。
首先是Department,我们只是添加了构造方法(在哪里修改的我也写到了注释里),如下:
package com.sunsy.crud.bean;
public class Department {
//以下是我们自己添加的
public Department() {
super();
}
public Department(Integer deptId, String deptName) {
super();
this.deptId = deptId;
this.deptName = deptName;
}
//以上是我们自己添加的
private Integer deptId;
private String deptName;
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName == null ? null : deptName.trim();
}
}
Employee.java,我们添加了构造方法,添加了一个属性department及其get\set方法,方便我们查询employee的时候把员工对应的部门也查询出来:
package com.sunsy.crud.bean;
public class Employee {
//以下自己添加
public Employee() {
super();
}
public Employee(Integer empId, String empName, String gender, String email, Integer dId) {
super();
this.empId = empId;
this.empName = empName;
this.gender = gender;
this.email = email;
this.dId = dId;
}
//以上自己添加
private Integer empId;
private String empName;
private String gender;
private String email;
private Integer dId;
//以下自己添加
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
//以上自己添加
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName == null ? null : empName.trim();
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender == null ? null : gender.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public Integer getdId() {
return dId;
}
public void setdId(Integer dId) {
this.dId = dId;
}
}
DepartmentExample.java和EmployeeExample.java这两个复杂查询相关的类我们没做任何修改,我就不往上复制了。代码后续我会放到github上和csdn的下载板块去的,到时候大家自己查就OK了。
EmployeeMapper.java里,我们添加两个接口,这两个接口让我们在查询员工信息的时候顺便把员工对应的部门信息也查询出来,如下:
package com.sunsy.crud.dao;
import com.sunsy.crud.bean.Employee;
import com.sunsy.crud.bean.EmployeeExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface EmployeeMapper {
long countByExample(EmployeeExample example);
int deleteByExample(EmployeeExample example);
int deleteByPrimaryKey(Integer empId);
int insert(Employee record);
int insertSelective(Employee record);
List<Employee> selectByExample(EmployeeExample example);
Employee selectByPrimaryKey(Integer empId);
//以下自己添加
//我们希望查询结果不仅有员工信息,还有员工所在的部门的信息
List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
//以上自己添加
int updateByExampleSelective(@Param("record") Employee record, @Param("example") EmployeeExample example);
int updateByExample(@Param("record") Employee record, @Param("example") EmployeeExample example);
int updateByPrimaryKeySelective(Employee record);
int updateByPrimaryKey(Employee record);
}
DepartmentMapper.java没做任何修改。
EmployeeMapper.xml里我们同样主要是为了查询员工信息时顺便把对应部门也查处了而做了一些修改,比着自己生成的xml改一改还是比较容易的,我感觉唯一需要注意的就是在employee类的department属性赋值时用association标签,如下(大部分都是自动生成的,偷个懒,直接全贴上去了,哪里是自己修改的在注释上标明了):
<?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="com.sunsy.crud.dao.EmployeeMapper">
<resultMap id="BaseResultMap" type="com.sunsy.crud.bean.Employee">
<id column="emp_id" jdbcType="INTEGER" property="empId" />
<result column="emp_name" jdbcType="VARCHAR" property="empName" />
<result column="gender" jdbcType="CHAR" property="gender" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="d_id" jdbcType="INTEGER" property="dId" />
</resultMap>
<!-- 以下自己添加 -->
<!-- 自定义的resultMap,员工信息和部门信息一块显示,这就是为啥我们要在Employee类里加一个department属性 -->
<resultMap type="com.sunsy.crud.bean.Employee" id="WithDeptResultMap">
<id column="emp_id" jdbcType="INTEGER" property="empId" />
<result column="emp_name" jdbcType="VARCHAR" property="empName" />
<result column="gender" jdbcType="CHAR" property="gender" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="d_id" jdbcType="INTEGER" property="dId" />
<association property="department" javaType="com.sunsy.crud.bean.Department">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
<!-- 以上自己添加 -->
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
emp_id, emp_name, gender, email, d_id
</sql>
<!-- 以下自己添加 -->
<!-- 我们希望查询结果不仅有员工信息,还有员工所在的部门的信息 -->
<sql id="WithDept_Column_List">
emp_id, emp_name, gender, email, d_id, dept_id, dept_name
</sql>
<!-- 以下两个select是实现将员工信息及其部门信息全部查询出来 -->
<select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="WithDept_Column_List" />
FROM tbl_emp
LEFT JOIN tbl_dept on tbl_emp.d_id=tbl_dept.dept_id
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
select
<include refid="WithDept_Column_List" />
FROM tbl_emp
LEFT JOIN tbl_dept on tbl_emp.d_id=tbl_dept.dept_id
where emp_id = #{empId,jdbcType=INTEGER}
</select>
<!-- 以上自己添加 -->
<select id="selectByExample" parameterType="com.sunsy.crud.bean.EmployeeExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from tbl_emp
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from tbl_emp
where emp_id = #{empId,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from tbl_emp
where emp_id = #{empId,jdbcType=INTEGER}
</delete>
<delete id="deleteByExample" parameterType="com.sunsy.crud.bean.EmployeeExample">
delete from tbl_emp
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="com.sunsy.crud.bean.Employee">
insert into tbl_emp (emp_id, emp_name, gender,
email, d_id)
values (#{empId,jdbcType=INTEGER}, #{empName,jdbcType=VARCHAR}, #{gender,jdbcType=CHAR},
#{email,jdbcType=VARCHAR}, #{dId,jdbcType=INTEGER})
</insert>
<insert id="insertSelective" parameterType="com.sunsy.crud.bean.Employee">
insert into tbl_emp
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="empId != null">
emp_id,
</if>
<if test="empName != null">
emp_name,
</if>
<if test="gender != null">
gender,
</if>
<if test="email != null">
email,
</if>
<if test="dId != null">
d_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="empId != null">
#{empId,jdbcType=INTEGER},
</if>
<if test="empName != null">
#{empName,jdbcType=VARCHAR},
</if>
<if test="gender != null">
#{gender,jdbcType=CHAR},
</if>
<if test="email != null">
#{email,jdbcType=VARCHAR},
</if>
<if test="dId != null">
#{dId,jdbcType=INTEGER},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="com.sunsy.crud.bean.EmployeeExample" resultType="java.lang.Long">
select count(*) from tbl_emp
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update tbl_emp
<set>
<if test="record.empId != null">
emp_id = #{record.empId,jdbcType=INTEGER},
</if>
<if test="record.empName != null">
emp_name = #{record.empName,jdbcType=VARCHAR},
</if>
<if test="record.gender != null">
gender = #{record.gender,jdbcType=CHAR},
</if>
<if test="record.email != null">
email = #{record.email,jdbcType=VARCHAR},
</if>
<if test="record.dId != null">
d_id = #{record.dId,jdbcType=INTEGER},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update tbl_emp
set emp_id = #{record.empId,jdbcType=INTEGER},
emp_name = #{record.empName,jdbcType=VARCHAR},
gender = #{record.gender,jdbcType=CHAR},
email = #{record.email,jdbcType=VARCHAR},
d_id = #{record.dId,jdbcType=INTEGER}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="com.sunsy.crud.bean.Employee">
update tbl_emp
<set>
<if test="empName != null">
emp_name = #{empName,jdbcType=VARCHAR},
</if>
<if test="gender != null">
gender = #{gender,jdbcType=CHAR},
</if>
<if test="email != null">
email = #{email,jdbcType=VARCHAR},
</if>
<if test="dId != null">
d_id = #{dId,jdbcType=INTEGER},
</if>
</set>
where emp_id = #{empId,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.sunsy.crud.bean.Employee">
update tbl_emp
set emp_name = #{empName,jdbcType=VARCHAR},
gender = #{gender,jdbcType=CHAR},
email = #{email,jdbcType=VARCHAR},
d_id = #{dId,jdbcType=INTEGER}
where emp_id = #{empId,jdbcType=INTEGER}
</update>
</mapper>
DepartmentMapper.xml没做任何修改。
至此Mybatis相关的东西就大功告成了,我们已经可以用mapper接口进行增删查改了,这种时候必须果断测试一下,感受一下成功的喜悦。
Spring的测试模块相信大家都比较熟了,直接贴代码了,在我们自己的com.sunsy.crud.test包下创建一个MapperTest测试类,如下(想测试啥就把啥的注释去掉,右键直接run junittest即可):
package com.sunsy.crud.test;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.sunsy.crud.dao.DepartmentMapper;
import com.sunsy.crud.dao.EmployeeMapper;
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class MapperTest {
@Autowired
DepartmentMapper departmentMapper;
@Autowired
EmployeeMapper employeeMapper;
@Autowired
SqlSession sqlSession;
@Autowired
SqlSessionFactory sqlSessionFactory;
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
@Test
public void testCRUD() {
// //测试插入部门
// departmentMapper.insertSelective(new Department(1, "研发部"));
// departmentMapper.insertSelective(new Department(2, "销售部"));
// //测试插入员工
// employeeMapper.insertSelective(new Employee(null, "sunsy", "M", "[email protected]", 1));
// //批量插入,需要创建一个可以执行批量操作的sqlSession
// EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//
//
// Long startTime1 = System.currentTimeMillis();
// for(int i = 0; i<1000; i++) {
// mapper.insertSelective(new Employee(null, i+"", "M", "[email protected]", 1));
// }
// Long endTime1 = System.currentTimeMillis();
// System.out.println("插入完成" + "耗时:" + (endTime1-startTime1));
// //测试查询
// Employee emp = employeeMapper.selectByPrimaryKey(1);
// System.out.println(emp.getDepartment());
//
// Employee emp1 = employeeMapper.selectByPrimaryKeyWithDept(1);
// System.out.println(emp1.getDepartment());
}
}
上边代码有个测试是批量插入,我们需要在applicationContext.xml里配置一个能支持批量操作的sqlSession,将如下配置放到applicationContext.xml里即可:
<!-- 配置一个可执行批量插入的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
不过在这里我有点疑惑,我写的和网上很多博主的配置是一模一样的,但是我丝毫没有感觉到在批量插入时效率的提高,不知道有没有大手子知道是咋回事,是不是我哪里写的有问题。。
好了,可能虽然即使也许maybe有点瑕疵,但是起码的功能我们已经测通了,下一章就正式进入我们的增删查改相关操作的编写。预知后事如何,且听下回分解。