1、引入依赖
org.mybatis
mybatis
3.5.7
junit
junit
4.12
test
mysql
mysql-connector-java
8.0.27
log4j
log4j
1.2.17
2、创建数据表
CREATE TABLE t_dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(20)
);
CREATE TABLE t_emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
age INT,
gender CHAR,
dept_id INT
);
INSERT INTO t_dept(dept_name) VALUES ('A'),('B'),('C');
INSERT INTO t_emp(emp_name,age,gender,dept_id) VALUES
('张三',20,'女',1),
('李四',22,'女',2),
('王五',21,'男',3),
('赵六',23,'男',1),
('田七',21,'女',3);
3、创建与数据表相对应 java 实体类
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Integer deptId;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender, Integer deptId) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
this.deptId = deptId;
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", deptId=" + deptId +
'}';
}
}
public class Dept {
private Integer deptId;
private String deptName;
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Dept() {
}
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;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
'}';
}
}
4、jdbc.properties 文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.username=root
jdbc.password=root
5、MyBaits 核心配置文件
6、工具类:
package com.chenyin.ssm.utils;
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.InputStream;
public class SqlSessionUtil {
public static SqlSession getSqlSession() {
try {
// 获取核心的配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 创建 SqlSessionFactoryBuilder 对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 通过核心配置文件多对应的字节输入流创建工厂类 SqlSessionFactory ,生产 SqlSession 对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
// 创建 SqlSession 对象(自动操作事务)
return sqlSessionFactory.openSession(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
7、log4j.xml配置文件
字段名和属性名不一致的情况,如何处理映射关系:
1、为查询的字段设置别名,和属性名一致
2、当字段符合 MySql 的要求使用,而属性符合 java 的要求使用驼峰,此时可以在 MyBatis 的核心文件中使用 setting 标签设置一个全局变量配置,可以自动将下划线映射为驼峰
如:emp_id -> empId
3、使用 resultMap 自定义映射处理
resultMap:设置自定义的映射关系
id:唯一表示
type:处理映射关系的实体类的类型
常用标签
id: 处理主键和实体类中属性的映射关系
result:处理普通字段和实体类中属性的映射关系
column:设置映射关系中的字段名,必须是sql 查询出的某个字段
property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名
代码示例:
EmpMapper 接口:
public interface EmpMapper {
/**
* 根据 empId 获取 emp 信息
* @param empId
* @return
*/
Emp getEmpById(@Param("empId") Integer empId);
}
EmpMapper.xml 配置文件:
配置核心文件:
测试类:
public class EmpMapperTest {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
@Test
public void getEmpById() {
Emp emp = empMapper.getEmpById(2);
System.out.println(emp);
// Emp{empId=2, empName='李四', age=22, gender='女', deptId=2}
}
}
EmpMapper 接口:
Emp getEmpById2(@Param("empId") Integer empId);
EmpMapper.xml 配置文件:
测试:
@Test
public void getEmpById() {
Emp emp = empMapper.getEmpById2(2);
System.out.println(emp);
// Emp{empId=2, empName='李四', age=22, gender='女', deptId=2}
}
处理多对一的映射关系:
1、级联方式处理映射关系
2、使用association处理映射关系
3、分布查询方式处理映射关系
修改 emp 实体类:
package com.chenyixin.ssm.pojo;
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Dept dept;
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
EmpMapper 接口:
/**
* 根据 empId 获取 emp 的所有信息(包括该员工的部门信息)
* @param empId
* @return
*/
Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);
EmpMapper.xml 配置文件:
测试:
@Test
public void getEmpAndDeptByEmpId() {
Emp emp = empMapper.getEmpAndDeptByEmpId(1);
System.out.println(emp);
// Emp{empId=1, empName='张三', age=20, gender='女', dept=Dept{deptId=1, deptName='A'}}
}
association:处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
注意:一对一的映射关系可以用多对一的方式去处理
EmpMapper 接口:
Emp getEmpAndDeptByEmpId2(@Param("empId") Integer empId);
EmpMapper.xml 配置文件:
测试:
@Test
public void getEmpAndDeptByEmpId2() {
Emp emp = empMapper.getEmpAndDeptByEmpId2(3);
System.out.println(emp);
// Emp{empId=3, empName='王五', age=21, gender='男', dept=Dept{deptId=3, deptName='C'}}
}
association:处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
select : 设置分布查询的 sql 的唯一标识(namespace.id)
column:将查询出的某个字段作为分布查询的 sql 条件
EmpMapper 接口:
/**
* 分布查询:根据员工 id 查询对应员工信息 及其 该员工所对应的部门信息 (第二步)
* @param deptId
* @return
*/
Dept getEmpAndDeptByStopTwo(@Param("deptId") Integer deptId);
DeptMapper 接口:
/**
* 分布查询:根据员工 id 查询对应员工信息 及其 该员工所对应的部门信息 (第一步)
* @param empId
* @return
*/
Emp getEmpAndDeptByStopOne(@Param("empId") Integer empId);
DeptMapper.xml 配置文件:
EmpMapper.xml 配置文件:
测试:(记得开启全局配置)
@Test
public void getEmpAndDeptByStopOne() {
Emp emp = empMapper.getEmpAndDeptByStopOne(4);
System.out.println(emp);
}
结果:(查询了两次)
概念:对于实体类关联的属性到需要使用时才查询。也叫懒加载。
在全局变量中设置延迟加载:
测试1:(以在全局设置中开启了延迟加载)
@Test
public void getEmpAndDeptByStopOne() {
Emp emp = empMapper.getEmpAndDeptByStopOne(4);
System.out.println(emp.getEmpName());
}
结果:
因为全局变量会对所有的分布查询开启延迟加载,但也可以在 Mapper配置文件中的resultMap 设置延迟加载。
association:
fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载
fetchType=“eager(立即加载) | lazy(延迟加载)”
测试2:(测试代码与测试1相同)(以在全局设置中开启了延迟加载,但也在Mapper配置文件中的resultMap 设置了延迟加载)
结果:
处理一对多的映射关系
1、collection
2、分布查询
准备:
修改 dept 实体类:
public class Dept {
private Integer deptId;
private String deptName;
private List emps;
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Dept() {
}
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;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
", emps=" + emps +
'}';
}
}
collection (其子标签与 association 子标签用法相同)
collection:处理一对多的映射关系(处理集合类型的属性)
ofType:设置集合类型的属性中存储的数据的类型
DeptMapper 接口:
/**
* 根据部门 id 查询部门以及部门中的员工信息
* @param deptId
* @return
*/
Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);
DeptMapper.xml 配置文件:
测试:
public class DeptMapperTest {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
@Test
public void getDeptAndEmpByDeptId() {
Dept dept = deptMapper.getDeptAndEmpByDeptId(1);
System.out.println(dept);
// Dept{deptId=1, deptName='A',
// emps=[Emp{empId=1, empName='张三', age=20, gender='女', dept=null},
// Emp{empId=4, empName='赵六', age=23, gender='男', dept=null}]}
}
}
DeptMapper 接口:
/**
* 通过分布查询 查询部门以及部门中的员工信息的第一步
* @param deptId
* @return
*/
Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);
EmpMapper 接口:
/**
* 通过分布查询 查询部门以及部门中的员工信息的第二步
* @param deptId
* @return
*/
Emp getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);
EmpMapper.xml 配置文件:
DeptMapper.xml 配置文件:
测试:
@Test
public void getDeptAndEmpByStepOne() {
Dept dept = deptMapper.getDeptAndEmpByStepOne(3);
System.out.println(dept);
}
结果:
字段名和属性名不一致的情况,如何处理映射关系:
1、为查询的字段设置别名,和属性名一致2、当字段符合 MySql 的要求使用,而属性符合 java 的要求使用驼峰,
此时可以在 MyBatis 的核心文件中使用 setting 标签设置一个全局变量配置,
可以自动将下划线映射为驼峰
如:emp_id -> empId3、使用 resultMap 自定义映射处理
resultMap:设置自定义的映射关系
id:唯一表示
type:处理映射关系的实体类的类型常用标签
id: 处理主键和实体类中属性的映射关系
result:处理普通字段和实体类中属性的映射关系
column:设置映射关系中的字段名,必须是sql 查询出的某个字段
property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名映射关系处理:
使用 resultMap 自定义映射处理
处理多对一的映射关系:
1、级联方式处理映射关系
2、使用 association 处理映射关系
3、分布查询方式处理映射关系
处理一对多的映射关系
1、collection
2、分布查询
resultMap:设置自定义的映射关系
id:唯一表示
type:处理映射关系的实体类的类型常用标签
id: 处理主键和实体类中属性的映射关系
result:处理普通字段和实体类中属性的映射关系
column:设置映射关系中的字段名,必须是sql 查询出的某个字段
property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名association:处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
select : 设置分布查询的 sql 的唯一标识(namespace.id)
column:将查询出的某个字段作为分布查询的 sql 条件
fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载
fetchType=“eager(立即加载) | lazy(延迟加载)”注意:一对一的映射关系可以用多对一的方式去处理
collection:处理一对多的映射关系(处理集合类型的属性)
property:设置需要处理映射关系的属性的属性名
ofType:设置集合类型的属性中存储的数据的类型
select : 设置分布查询的 sql 的唯一标识(namespace.id)
column:将查询出的某个字段作为分布查询的 sql 条件
fetchType:在开启了延迟加载的环境中,通过该属性设置当前分布查询是否使用延迟加载
fetchType=“eager(立即加载) | lazy(延迟加载)”注意:多对多的映射关系可以用一对多的方式去处理
全局变量的设置: