Mybatis 简单练习,自定义sql关联查询
目录结构
mybatis-02/
├── pom.xml
└── src/├── main/│ ├── java/│ │ └── com/│ │ └── demo/│ │ ├── mapper/│ │ │ ├── DepartMapper.java│ │ │ ├── DepartMapper.xml│ │ │ ├── EmployeeMapper.java│ │ │ └── EmployeeMapper.xml│ │ ├── model/│ │ │ ├── Depart.java│ │ │ └── Employee.java│ │ ├── test/│ │ │ ├── DepartTest.java│ │ │ └── EmployeeTest.java│ │ └── util/│ │ └── MybatisUtil.java│ └── resources/│ ├── db.properties│ └── mybatis-config.xml└── test/└── java/└── com/└── demo/ // (空目录)
该项目是一个基于MyBatis框架的员工和部门管理的模拟项目demo,主要实现以下功能:
1. 技术架构
- 核心框架 :MyBatis(ORM持久层框架)
- 数据库 :MySQL(通过 db.properties 配置连接信息)
- 项目构建 :Maven(通过 pom.xml 管理依赖)
2. 主要功能
(1)数据模型设计
- 部门表(Depart) :包含部门ID(depid)和部门名称(depname)
- 员工表(Employee) :包含员工ID、姓名、薪水、入职日期、地址和部门ID(多对一关联部门)
(2)数据库操作
- 部门管理 :
- 通过 DepartMapper 实现部门查询,支持级联查询部门下的所有员工(一对多关系)
- 员工管理 :
- 基础查询:查询所有员工信息(关联部门名称)
- 条件查询:根据地址模糊查询和薪水范围筛选员工
- 更新操作:动态更新员工信息(支持部分字段更新)
- 批量查询:通过员工ID数组批量查询员工
(3)技术实现要点
- MyBatis核心配置 :
- mybatis-config.xml 配置数据库环境和映射器扫描
- 自定义 MybatisUtil 工具类管理SqlSession生命周期
- 高级映射 :
- 使用 处理实体类与数据库表字段映射
- 通过 实现员工到部门的多对一关联
- 通过 实现部门到员工的一对多关联
- 动态SQL :
- 使用 和 实现条件查询
- 使用 实现批量ID查询
3. 项目结构特点
- 采用标准MVC分层架构,分离模型(model)、映射器(mapper)和工具类(util)
- 配置文件与代码分离,通过属性文件管理数据库连接信息
- SQL语句与Java代码解耦,统一在XML映射文件中维护
总结
该项目是一个典型的MyBatis入门示例,演示了如何使用MyBatis进行数据库CRUD操作、处理关联关系及编写动态SQL,适合作为MyBatis框架的学习案例。
实体类
package com.demo.model;import java.util.List;public class Depart {private Integer depid;private String depname;
//处理一对多的关联方式private List<Employee> employees;public Integer getDepid() {return depid;}public void setDepid(Integer depid) {this.depid = depid;}public String getDepname() {return depname;}public void setDepname(String depname) {this.depname = depname;}public List<Employee> getEmployees() {return employees;}public void setEmployees(List<Employee> employees) {this.employees = employees;}
}package com.demo.model;import java.util.Date;public class Employee {private Integer empid;private String empname;private Double bsaralry;private Date hiredate;private String address;private Integer depid;//处理多对一的关联private Depart depart;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;}public Double getBsaralry() {return bsaralry;}public void setBsaralry(Double bsaralry) {this.bsaralry = bsaralry;}public Date getHiredate() {return hiredate;}public void setHiredate(Date hiredate) {this.hiredate = hiredate;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getDepid() {return depid;}public void setDepid(Integer depid) {this.depid = depid;}public Depart getDepart() {return depart;}public void setDepart(Depart depart) {this.depart = depart;}
}
mapper.java
package com.demo.mapper;import com.demo.model.Depart;public interface DepartMapper {Depart getDepartByDepname(String depname);
}package com.demo.mapper;import com.demo.model.Employee;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface EmployeeMapper {List<Employee>getEmpList();List<Employee> getEmployeeByAddressAndBsaralry(@Param("address") String address,@Param("bsaralry") Double bsaralry);int updateEmployee(Employee employee);List<Employee> getEmpsByEmpId(Integer[] idArray);
}
mapper.xml
<?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.demo.mapper.DepartMapper"><resultMap id="departResultMap" type="com.demo.model.Depart"><id property="depid" column="did"></id><result property="depname" column="depname"></result>
<!--collection:处理一堆多关联关键节点property:对应的是实体类中属性的名称ofType:描述该集合中的每个元素的类型--><collection property="employees" ofType="com.demo.model.Employee"><id property="empid" column="empid"></id><result property="empname" column="empname"></result><result property="bsaralry" column="bsaralry"></result><result property="hiredate" column="hiredate"></result><result property="address" column="address"></result><result property="depid" column="depid"></result></collection></resultMap><!--parameterType="java.lang.String" 或string,,小写 --><select id="getDepartByDepname" parameterType="java.lang.String" resultMap="departResultMap">selectd.depid as did,d.depname,e.*from employee e,depart dwhere d.depid=e.depid and depname=#{depname}</select>
</mapper><?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.demo.mapper.EmployeeMapper"><resultMap id="empResultMap" type="com.demo.model.Employee"><!--private Integer empid;private String empname;private String bsaralry;private Date hiretime;private String address;private Integer depid;
--><!--1.id节点:property:实体类中的oid(实体类中唯一能够表示一个对象的属性,,主键),也就是和结果集对应的实体类中的属性column:就是结果集中的主键字段2.result节点:property:实体类中的属性名column:结果集中的字段名property=“与实体类中的名一致”column=“与数据库中的一致” --><id property="empid" column="empid"></id><result property="empname" column="empname"></result><result property="bsaralry" column="bsaralry"></result><result property="hiredate" column="hiredate"></result><result property="address" column="address"></result><result property="depid" column="depid"></result><!--//处理多对一的关联private Depart depart;--><!-- association节点,专门写多对一(一对一)property:对应实体类中的属性名JavaType:对应该属性的Java类型名--><association property="depart" javaType="com.demo.model.Depart"><id property="depid" column="did"></id><result property="depname" column="depname"></result></association></resultMap><select id="getEmpList" resultMap="empResultMap">select e.*,d.depid as did,depnamefrom employee einner join depart d on e.depid = d.depid</select><!-- <!–动态sql语句 –>--><!-- <select id="getEmployeeByAddressAndBsaralry" resultType="com.demo.model.Employee">--><!-- select * from employee--><!--<!–<where></where> 1.如果有条件满足的话,那么久拼装where关键字,如果没有的话就不拼接关键字--><!--2.如果在sql语句条件的前面有and或or的时候,会自动去掉--><!--–>--><!-- <where>--><!-- <if test="address!=null and address!=''">--><!-- <!–address like '%福建省%'–>--><!-- <!–concat拼接字符串的函数–>--><!-- address like concat ('%',#{address},'%')--><!-- </if>--><!-- <!–转义符–>--><!-- <if test="bsaralry!=null">--><!-- and bsaralry >#{bsaralry}--><!-- </if>--><!-- </where>--><!-- </select>--><!--动态sql语句 --><select id="getEmployeeByAddressAndBsaralry" resultType="com.demo.model.Employee">select * from employee<!--prefix:前缀,代表trim节点内sql片段的开始部分prefixOverrides:用来描述去掉sql片段中and或者or的关键字--><trim prefix="where" prefixOverrides="and |or"><if test="address!=null and address!=''">and address like concat ('%',#{address},'%')</if><!--转义符--><if test="bsaralry!=null"><!-- >转义符,抓成>大于 -->and bsaralry >#{bsaralry}</if></trim></select><update id="updateEmployee" parameterType="com.demo.model.Employee">update employee<set><if test="empname!=null and empname!=''">empname=#{empname},</if><if test="bsaralry!=null">bsaralry=#{bsaralry},</if><if test="hiredate!=null">hiredate=#{hiredate},</if><if test="address!=null and address!=''">address=#{address},</if><if test="depid!=null">depid=#{depid}</if></set><where><!--test="实体类中的属性"--><if test="empid!=null">empid=#{empid}</if></where></update><select id="getEmpsByEmpId" resultType="com.demo.model.Employee">select *from employeewhere empid in<!--for(Employee e :list){}1. foreach节点中属性的说明array:接受数组,是一个集合open:描述的是in后面左面的(close:描述的是in后面右面的)separator:描述的是数组中的元素的,分隔符item:迭代的变量2.迭代的集合类型可以是数组、List、Set、Map、Map.Entry。根据阅读官网描述如下:你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。--><foreach collection="array" open="(" close=")" separator="," item="empid">#{empid}</foreach></select>
<!--choose when otherwise --></mapper>
单元测试
package com.demo.test;import com.demo.mapper.DepartMapper;
import com.demo.model.Depart;
import com.demo.model.Employee;
import com.demo.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class DepartTest {@Testpublic void getDepartByDepname() {SqlSession sqlSession = null;try {sqlSession = MybatisUtil.createSqlSession();Depart depart = sqlSession.getMapper(DepartMapper.class).getDepartByDepname("财务部");if (null != depart) {System.out.println("部门编号:" + depart.getDepid());System.out.println("部门名称:" + depart.getDepname());System.out.println("*************************************");//关键List<Employee> employees = depart.getEmployees();if (null != employees && employees.size() > 0) {for (Employee e : employees) {System.out.println(e.getEmpid() + "--" + e.getEmpname() + "--" + e.getBsaralry() + "--"+ e.getHiredate() + "--" + e.getAddress() + "--" + e.getDepid());}}}sqlSession.commit();} catch (Exception e) {e.printStackTrace();} finally {MybatisUtil.closeSqlSession(sqlSession);}}
}package com.demo.test;import com.demo.mapper.EmployeeMapper;
import com.demo.model.Employee;
import com.demo.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.Date;
import java.util.List;public class EmployeeTest {@Testpublic void getEmpList() {SqlSession sqlSession = null;try {sqlSession = MybatisUtil.createSqlSession();List<Employee> list = sqlSession.getMapper(EmployeeMapper.class).getEmpList();if (null != list) {for (Employee e : list) {System.out.println(e.getEmpid() + "--" + e.getEmpname() + "--" + e.getBsaralry() + "--"+ e.getHiredate() + "--" + e.getAddress() + "--" + e.getDepid() + "--" + e.getDepart().getDepid() + "--" +e.getDepart().getDepname());System.out.println("==============================");}}sqlSession.commit();} catch (Exception e) {e.printStackTrace();} finally {MybatisUtil.closeSqlSession(sqlSession);}}@Testpublic void getEmployeeByAddressAndBsaralry() {SqlSession sqlSession = null;try {sqlSession = MybatisUtil.createSqlSession();//动态sql只用if,这两个值必须都要写String address = "市";Double bsaralry = null;List<Employee> list = sqlSession.getMapper(EmployeeMapper.class).getEmployeeByAddressAndBsaralry(address, bsaralry);if (null != list) {for (Employee e : list) {System.out.println(e.getEmpid() + "--" + e.getEmpname() + "--" + e.getBsaralry() + "--"+ e.getHiredate() + "--" + e.getAddress() + "--" + e.getDepid());System.out.println("==============================");}}sqlSession.commit();} catch (Exception e) {e.printStackTrace();} finally {MybatisUtil.closeSqlSession(sqlSession);}}@Testpublic void updateEmployee() {SqlSession sqlSession = null;try {sqlSession = MybatisUtil.createSqlSession();Employee employee = new Employee();employee.setEmpid(1012);employee.setEmpname("孙策");employee.setBsaralry(10000D);employee.setAddress("新疆乌鲁木齐市");employee.setHiredate(new Date());employee.setDepid(1);int rows = sqlSession.getMapper(EmployeeMapper.class).updateEmployee(employee);System.out.println("影响行数:" + rows);sqlSession.commit();} catch (Exception e) {e.printStackTrace();} finally {MybatisUtil.closeSqlSession(sqlSession);}}@Testpublic void getEmpsByEmpId() {SqlSession sqlSession = null;try {sqlSession = MybatisUtil.createSqlSession();Integer[] idArray =new Integer[] {1002,1003,1004,1005,1006};List<Employee> list = sqlSession.getMapper(EmployeeMapper.class).getEmpsByEmpId(idArray);if (null != list) {for (Employee e : list) {System.out.println(e.getEmpid() + "--" + e.getEmpname() + "--" + e.getBsaralry() + "--"+ e.getHiredate() + "--" + e.getAddress() + "--" + e.getDepid());System.out.println("==============================");}}sqlSession.commit();} catch (Exception e) {e.printStackTrace();} finally {MybatisUtil.closeSqlSession(sqlSession);}}
}
工具类
package com.demo.util;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.Reader;public class MybatisUtil {private static SqlSessionFactory factory;static {//1.创建SqlSessionFactoryBuilder对象SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();try {//2.创建SqlSessionFactory 对象String configFile = "mybatis-config.xml";Reader reader = Resources.getResourceAsReader(configFile);factory = builder.build(reader);} catch (IOException e) {e.printStackTrace();}}/*** 创建SqlSession对象** @return*/public static SqlSession createSqlSession() {/*** 1)openSession(boolean)默认为true,当为true时候自动提交事务* 2)添加,修改,删除必须提交事物,查询可以提交也可以不提交*/return factory.openSession(false);//默认值为true}//关闭public static void closeSqlSession(SqlSession sqlSession){if (null!=sqlSession){sqlSession.close();}}
}
配置文件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
username=root
password=1234
mybatis-conig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--添加数据库的属性文件 --><properties resource="db.properties"></properties><!--开发模式,测试模式,线上模式我们这配置成开发模式--><environments default="development"><environment id="development"><!-- 设置事物模式--><transactionManager type="jdbc"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers>
<!-- 相对地址--><mapper resource="com\demo\mapper\EmployeeMapper.xml"></mapper><mapper resource="com\demo\mapper\DepartMapper.xml"></mapper></mappers>
</configuration>
pom.xm
<?xml version="1.0" encoding="UTF-8"?><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/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.demo</groupId><artifactId>employee-mybatis-02</artifactId><version>1.0-SNAPSHOT</version><name>employee-mybatis-02</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.7</maven.compiler.source><maven.compiler.target>1.7</maven.compiler.target><mybatis.version>3.2.8</mybatis.version><mysql.version>8.0.33</mysql.version><junit.version>4.12</junit.version></properties><dependencies><!-- Mybatis框架 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- MySql数据库 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--Junit 测试框架 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency></dependencies><!--配置资源文件--><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource></resources></build>
</project>