返回map
Map<String,Object> getEmpByResMap(Integer id);
<select id="getEmpByResMap" resultType="map">
select * from tb_employee where id = #{id}
</select>
@Test
public void test9() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Map<String,Object> map = mapper.getEmpByResMap(4);
System.out.println(map.get("last_name"));
}finally {
openSession.close();
}
}
返回一条记录的map,key就是列名,值就是对应值,如果是多条记录封装一个map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean对象
我们需要用标签声明我们想要的用哪个属性作为主键
@MapKey("id")
Map<String,Employee> getEmpByLastNameLikeResMap(String lastName);
<select id="getEmpByLastNameLikeResMap" resultType="com.figsprite.bean.Employee">
select * from tb_employee where last_name like #{lastName}
</select>
@Test
public void test10() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Map<String,Employee> map =mapper.getEmpByLastNameLikeResMap("%吴%");
for(Map.Entry<String, Employee> mapi:map.entrySet()){
System.out.println(mapi.getValue().getLastName());
}
}finally {
openSession.close();
}
}
resultMap
如果在JavaBean的属性名和数据库列名不相同,之前讲了一个起别名的方法,另外就是开启setting的驼峰命名开关,还有一种就是自定义resultMap,实现高级结果集映射。
为了方便测试效果,先将最早在setting中的配置关闭,此时运行getEmpById,发现lastName值为null,接下来我们采用resultMap完成之前的效果,现在映射文件前部,声明resultMap标签,指定该标签的id,方便我们引用,接着指定相关类,当然这里也可以使用别名。在resultMap中有<id>(主键),<result>(普通属性)标签,用来指定JavaBean属性与数据库类名对应,
<resultMap id="Emp" type="com.figsprite.bean.Employee"> <id property="id" column="id"/> <result property="lastName" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> </resultMap>
其实,其他命名没错的属性,可以不必在写<result>,不过推荐都写。
接着我们就可以在数据操作的标签里使用resultMap属性,填入指定id名,表示返回结果的map,注意resultMap和resultType只能二选一
<select id="getEmpById" resultMap="Emp">
select * from tb_employee where id =#{id}
</select>
此时执行,lastName里就有值了
@Test
public void test1() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlOpenSession = sqlSessionFactory.openSession();
try{
EmployeeMapperPlus employeeMapperPlus = sqlOpenSession.getMapper(EmployeeMapperPlus.class);
Employee employee = employeeMapperPlus.getEmpById(3);
System.out.println(employee);
}finally {
sqlOpenSession.close();
}
}
Employee{id=3, lastName='Tom', gender='1', email='qwewqeqw'}
resultMap 级联属性查询
接下来讲讲resultMap的强大之处,假设每个员工对应一个部门,并且部门信息封装在JavaBean中,如下
我们接下来的任务就是查出员工信息的同时,查出其所在部门的信息,
先更改一下表信息:
USE mybatis_learn;
CREATE TABLE tb_department(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
department_name VARCHAR(255)
);
ALTER TABLE tb_employee ADD COLUMN d_id INT(11);
ALTER TABLE tb_employee ADD CONSTRAINT fk_emp_dep
FOREIGN KEY(d_id) REFERENCES tb_department(id);
然后创建一个department类:
public class Department { private Integer id; private String departmentName; }
填写sql语句
<select id="getEmpAndDep" resultMap="EmpAndDep">
SELECT e.`id` id,e.`last_name` last_name,e.`gender` gender,e.`d_id` d_id,d.`id` did,d.`department_name` dep_name
FROM tb_employee e,tb_department d
WHERE e.id = 3 AND d.id=e.d_id;
</select>
<resultMap id="EmpAndDep" type="com.figsprite.bean.Employee">
<id property="id" column="id"/>
<result property="lastName" column="last_name"/>
<result property="gender" column="gender"/>
<result property="department.id" column="d_id"/>
<result property="department.departmentName" column="dep_name"/>
</resultMap>
这里采用级联方式填入result的属性
@Test
public void test1() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlOpenSession = sqlSessionFactory.openSession();
try{
EmployeeMapperPlus employeeMapperPlus = sqlOpenSession.getMapper(EmployeeMapperPlus.class);
Employee employee = employeeMapperPlus.getEmpAndDep(3);
System.out.println(employee);
}finally {
sqlOpenSession.close();
}
}
Employee{id=3, lastName='Tom', gender='1', email='null', department=Department{id=1, departmentName='财务部'}}
resultMap <association>联合指定JavaBean对象查询
我们还可以使用<association>标签进行查询,这个标签下有两个关键属性
property:指定那个属性是联合对象
javaType:指定这个属性对象的类型[不能省略]
<resultMap id="EmpAndDep" type="com.figsprite.bean.Employee">
<id property="id" column="id"/>
<result property="lastName" column="last_name"/>
<result property="gender" column="gender"/>
<association property="department" javaType="com.figsprite.bean.Department">
<id property="id" column="did"/>
<result property="departmentName" column="dep_name"/>
</association>
</resultMap>
resultMap <association>分步查询
大多数情况下,我们都会为每一个Dao层接口配置一个***Mapper.xml文件,比如本例子中,我们可以利用DepartmnetMapper.xml中查询department的<select>来查询。
我们可以先查员工,通过员工的d_id再来查部门
第一步:先按照员工id查询员工名信息
第二步:根据查询员工信息的d_id值去部门表查出部门信息
第三步:部门信息设置到员工中
property:指定哪个属性
select:表示当前属性是调用select指定的方法查出的结果
column:指定将哪一列的值传给这个方法
<resultMap id="EmpAndDepStep" type="com.figsprite.bean.Employee">
<id property="id" column="id"/>
<result property="lastName" column="last_name"/>
<result property="email" column="email"/>
<result property="gender" column="gender"/>
<association property="department"
select="com.figsprite.dao.DepartmentMapper.getDepById"
column="d_id">
</association>
</resultMap>
@Test
public void test1() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlOpenSession = sqlSessionFactory.openSession();
try{
EmployeeMapperPlus employeeMapperPlus = sqlOpenSession.getMapper(EmployeeMapperPlus.class);
Employee employee = employeeMapperPlus.getEmpByIdStep(3);
System.out.println(employee);
}finally {
sqlOpenSession.close();
}
}
DEBUG [main] - ==> Preparing: select * from tb_employee where id =?
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - ====> Preparing: select id,department_name from tb_department where id=?
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <==== Total: 1
DEBUG [main] - <== Total: 1
观察日志文件,可以看出,Mybatis向数据库发送了两条SQL语句
分步查询的延迟加载
在上个例子中,我们通过Employee查询Department,我们每次查询Employee对象的时候,都将一起查询Department,但是如果可以将部门信息查询变成只有在我们使用部门信息时才去查询的方式,那么就非常节约数据库资源了。
我们只要在全局配置文件中的<setting>字段加上两个属性即可
lazyLoadingEnabled
aggressiveLazyLoading
lazyLoadingEnabled 是延迟加载的全局开关,aggressiveLazyLoading当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
接下来做一个测试,我们只要打印employee中的lastName
@Test
public void test1() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlOpenSession = sqlSessionFactory.openSession();
try{
EmployeeMapperPlus employeeMapperPlus = sqlOpenSession.getMapper(EmployeeMapperPlus.class);
Employee employee = employeeMapperPlus.getEmpByIdStep(3);
System.out.println(employee.getLastName());
}finally {
sqlOpenSession.close();
}
}
}
在日志文件中可以清楚的看到,Mybatis只发了一条SQL
DEBUG [main] - ==> Preparing: select * from tb_employee where id =?
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <== Total: 1
我们可以试着把<setting>中的两个标签注释掉,查看日志
DEBUG [main] - ==> Preparing: select * from tb_employee where id =?
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - ====> Preparing: select id,department_name from tb_department where id=?
DEBUG [main] - ====> Parameters: 1(Integer)
DEBUG [main] - <==== Total: 1
DEBUG [main] - <== Total: 1
区别显而易见。
DepartmentMapper.xml
DepartmentMapper.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 namespace="com.figsprite.dao.DepartmentMapper"> <select id="getDepById" resultType="department"> select id,department_name from tb_department where id=#{id} </select> </mapper>

package com.figsprite.dao; import com.figsprite.bean.Department; public interface DepartmentMapper { Department getDepById(Integer id); }