2,MyBatis映射文件解析
MyBatis最强大的地方就在于它的语句映射,正由于它的强大,映射对应的xml文件代码编写就会相应简单。可以明显感知到比同功能的jdbc代码少了很多很多。MyBatis致力于减少使用成本,让用户更专注于SQL代码。
SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):
- cache:该命名空间的缓存配置。
- cache-ref:引用其它命名空间的缓存配置。
- resultMap:描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
- sql:可被其它语句引用的可重用语句块。
- insert:映射插入语句。
- update:映射更新语句。
- delete:映射删除语句。
- select:映射查询语句。
2.1,先准备表
create database if not exists mydb;
use mydb;
CREATE TABLE tb_depart(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(20)
);
CREATE TABLE tb_employee(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(20),
age int,
did int
);
INSERT INTO tb_depart(name) VALUES('武装部');
INSERT INTO tb_employee(name, age, did) VALUES('赵子龙', 30, 1);
INSERT INTO tb_employee(name, age, did) VALUES('关羽', 35, 1);
2.2,insert
这个元素用于执行insert语句向数据库中插入数据
2.2.1,添加方法
在EmployeeMapper接口中添加插入方法
public interface EmployeeMapper {
// 插入
void add(Employee employee);
}
2.2.2,编写映射
在EmployeeMapper.xml文件中实现add方法
<?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.xianopeng.mapper.EmployeeMapper">
<!-- 插入 -->
<insert id="add" parameterType="Employee">
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
insert into tb_employee(name,age,did) values (#{name}, #{age}, #{did})
</insert>
</mapper>
2.2.3,测试
@Test
public void testAdd() {
SqlSession session = MyBatisUtil.openSession();
try {
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Employee employee = new Employee().setName("张飞").setAge(20).setDid(1);
mapper.add(employee);
session.commit();
System.out.println("employee = " + employee);
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}
}
2.3,select
这个元素用于查询数据的顶级元素,主属性如下:
- id:它是一个唯一标识,与接口中的方法名称一致。
- parameterType:将会传入这条语句的参数的类全限定名或别名,这个属性是可选的。
- resultType:返回的结果是集合时是定义集合中元素的类型。它可以使用全限定名,也可以使用别名。它不能和 resultMap 同时使用。
- resultMap:对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。
2.3.1,添加查询方法
在EmployrrMapper接口中添加查询方法
// 查询
List<Employee> getEmployeeByName(String name);
2.3.2,实现
在EmployeeMapper.xm文件中写对应的实现
<select id="getEmployeeByName" resultType="Employee">
select id,name,age,did from tb_employee where name like #{name}
</select>
2.3.3,测试
@Test
public void testGetEmployeeByName() {
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
String name = "刘";
String s = "%" + name + "%";
List<Employee> employees = mapper.getEmployeeByName(s);
employees.forEach(System.out::println);
}
2.4,带参数查询
在 MyBatis 中,查询语句是可以带参数,当参数是一个的时候很简单,当参是多个的时候,我们可以把它封装到实体对象中,也可以用逗号的方式来分隔。
2.4.1,添加方法
// 多参数查询
List<Employee> getEmployeeByNameAndAge(String name, int age);
2.4.2,实现
<!-- 多参数查询 -->
<select id="getEmployeeByNameAndAge" resultType="Employee">
select id,name,age,did from tb_employee where name=#{param1} and age=#{param2}
</select>
2.4.3测试
// 多参数查询
@Test
public void testGetEmployeeByNameAndAge() {
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
List<Employee> employees = mapper.getEmployeeByNameAndAge("刘备", 20);
employees.forEach(System.out::println);
}
2.5,#{}和${}
在执行sql语句时,我们使用#{}来给参数传值
例如:
<select id="getEmployeeByAnnotation" resultType="Employee">
select id,name,age,did from tb_employee where name=#{name} and age=#{age}
</select>
最终在mybatis中会执行的sql语句则为:
select id,name,age,did from tb_employee where name=? and age=?
这种方式是使用的 PreparedStatement 对象来处理的。
还有一种方法是使用${}传值,它会将给定值拼接到sql语句中:
例如:
<select id="getEmployeeByAnnotation" resultType="Employee">
select id,name,age,did from tb_employee where name=${name} and age=${age}
</select>
在mybatis中执行的sql语句为:
select id,name,age,did from tb_employee where name=刘备 and age=20
实际上它使用的就是 Statement 对象来处理 SQL,所以我们在开发中,不要使用 ${} ,而是使用 #{} 来赋值。
2.6,将查询结果封装到map中
2.6.1,添加方法
Map<String, Object> getEmployeeById(int id);
2.6.2,实现
<select id="getEmployeeById" resultType="map">
select id,name,age,did from tb_employee where id=#{id}
</select>
2.6.3,测试
@Test
public void testGetEmployeeById() {
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Map<String, Object> result = mapper.getEmployeeById(5);
System.out.println(result);
}
2.6.4,查询多条时的修改
将结果封装到Employee对象中,将Map集合改为Map<Integer,Employee>
@MapKey("id")
Map<Integer, Employee> getEmployees();
实现:
<select id="getEmployees" resultType="Employee">
select id,name,age,did from tb_employee
</select>
测试:
@Test
public void testGetEmployees() {
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Map<Integer, Employee> result = mapper.getEmployees();
System.out.println(result);
}
2.7,resultMap
resultMap元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap
能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
2.7.1,添加方法
Employee findEmployeeById(int id);
2.7.2,实现
<resultMap id="rm" type="Employee">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="did" column="did"/>
</resultMap>
<select id="findEmployeeById" resultMap="rm">
select id,name,age,did from tb_employee where id=#{id}
</select>
在 select 标签上使用 resultMap 属性来指定返回的结果集,它的值必须与某个 resultMap 标签定义的 id 属性的值一致。
resultMap 标签说明:
- id:用于给这个配置取一个唯一的名称,便于使用时引用。
- type:定义这就结果集的返回类型,可以是别名,也可以是全限定名。
resultMap子标签介绍:
- id:用来定义主键关联
- property:实体类中哪个属性作为主键
- column:表中哪个字段作为主键
- result:用于定义除了主键外的字段关联
- property:实体类中的属性名
- column:表中的字段
2.7.3,测试
@Test
public void testFindEmployeeById() {
SqlSession session = MyBatisUtil.openSession();
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Employee employee = mapper.findEmployeeById(5);
System.out.println(employee);
}
2.8,association
2.8.1,在员工类中添加对部门的关联
@Data
@Accessors(chain = true)
public class Employee {
private Integer id;
private String name;
private int age;
private Integer did;
// 关联部门,它是多对一关系
private Department depart;
}
2.8.2,在部门类接口添加方法
根据部门编号查询部门名称
// 根据ID查询部门
Department getDepartmentById(int id);
实现:
<mapper namespace="com.xianopeng.mapper.DepartmentMapper">
<!-- 根据ID查询部门 -->
<select id="getDepartmentById" resultType="Department">
select id,name from tb_depart where id=#{id};
</select>
</mapper>
2.8.3,添加员工方法
Employee getById(int id);
实现:
<resultMap id="rm1" type="Employee">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="did" property="depart.id"/>
<result column="dname" property="depart.name"/>
</resultMap>
<select id="getById" resultMap="rm1">
select e.id id, e.name name, age, d.name dname
from tb_employee e, tb_depart d
where e.did=d.id and e.id=#{id}
</select>
2.8.4,使用association配置联合查询:
<resultMap id="rm1" type="Employee">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<association property="depart" javaType="Department">
<id property="id" column="did"/>
<result property="name" column="dname"/>
</association>
</resultMap>
<select id="getById" resultMap="rm1">
select e.id id, e.name name, age, d.id did, d.name dname
from tb_employee e, tb_depart d
where e.did=d.id and e.id=#{id}
</select>
association 标签来实现联合查询,属性说明如下:
- property:用于指定返回类型对象(Employee)中那个属性来作为联合查询
- javaType:用于定义被关联的属性对应的 Java 类型
2.9,collection
关联查询,查询部门时候,将部门下的员工也查询出来
2.9.1,修改部门实体类
@Data
@Accessors(chain = true)
public class Department {
private Integer id;
private String name;
// 一对多
private Set<Employee> emps;
}
2.9.2,实现
<resultMap id="depMap" type="Department">
<id property="id" column="did" />
<result property="name" column="dname"/>
<collection property="emps" ofType="Employee">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
</collection>
</resultMap>
<select id="getById" resultMap="depMap">
select d.id did,d.name dname, e.id id,e.name name,age
from tb_depart d left join tb_employee e on d.id = e.did
where d.id=#{id};
</select>
2.9.3,测试
@Test
public void testGetByDid() {
SqlSession session = MyBatisUtil.openSession();
DepartmentMapper mapper = session.getMapper(DepartmentMapper.class);
Department department = mapper.getById(1);
System.out.println(department.getName());
department.getEmps().forEach(System.out::println);
}