mybatis中的resultMap
mybatis中的resultMap,结果映射,将返回的数据进行更加高级的自定义规则设置,resultMap 元素是 MyBatis 中最重要最强大的元素
结果映射中还可以使用resultType,它可以指定返回的数据类型,如map
<select id="getEmp" resultType="map"> select * from emp </select>
映射到map中并不是很好的结果,因为我们不是很清晰的知道map中的数据,所有我们一般指定javabean类型返回,如上面的例子中,查询的emp数据,
我们写一个Emp类来进行参数的封窗。
@Data
public class Emp { private Long id; private String name; private String gender; private String email; }
我们的xml就可以这样写:
<select id="getEmp" resultType="com.mybatis.bean.Emp"> select id,name,gender,emailfrom emp
</select>
上面使用resultType的做法,我们可以使用resultMap,实现相同的结果
<!--id 唯一标识--> <resultMap id="myEmp" type="com.mybatis.bean.Emp"> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="gender" property="gender"></result> <result column="email" property="email"></result> </resultMap> <select id="getEmp" resultMap="myEmp"> select id,name,gender,email from emp </select>
resultType和resultMap不能同时使用,如果Emp中有一个对象的属性,那么直接使用resultType返回 com.mybatis.bean.Emp将会有问题;
如:Emp中有一个属性dept
@Data public class Emp { private Long id; private String name; private String gender; private String email; private Dept dept;
Dept:
@Data public class Dept { private Long deptId; private String deptName;
xml:
<select id="getEmpAndDept" resultType="com.mybatis.bean.Emp"> SELECT e.id,e.name,e.gender,e.email,d.dept_id,d.dept_name FROM emp e, dept d where e.dept_id = d.dept_id and e.id = #{id} </select>
这时候我们发现返回的数据中dept是null,所以这时候我们就可以使用resultMap自定义的映射规则了
第一种方式:
<!--id 唯一标识--> <resultMap id="myEmpDept" type="com.mybatis.bean.Emp"> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="gender" property="gender"></result> <result column="email" property="email"></result> <result column="dept_id" property="dept.deptId"></result> <result column="dept_name" property="dept.deptName"></result> </resultMap>
第二种方式:使用association
<resultMap id="myEmpDept" type="com.mybatis.bean.Emp"> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="gender" property="gender"></result> <result column="email" property="email"></result> <!--指定javabean对象,emp的属性dept property:指定emp的属性dept javaType:指定属性的类型com.mybatis.bean.Dept --> <association property="dept" javaType="com.mybatis.bean.Dept"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> </association> </resultMap>
SQL这里的resultMap指定上面的id属性
<select id="getEmpAndDept" resultMap="myEmpDept"> SELECT e.id,e.name,e.gender,e.email,d.dept_id,d.dept_name FROM emp e, dept d where e.dept_id = d.dept_id and e.id = #{id} </select>
这样就可以返回的dept就有数据了。
如果Dept中定义的类型是集合:一个部门对应多个员工
@Data
public class Dept {
private Long deptId;
private String deptName;
private List<Emp> emp;
这时候使用association就不行了,需要使用collection
<resultMap id="myDepts" type="com.mybatis.bean.Dept"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> <!--property:Dept中的emp属性 ofType:集合里面元素的类型 --> <collection property="emp" ofType="com.mybatis.bean.Emp"> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="gender" property="gender"></result> <result column="email" property="email"></result> </collection> </resultMap> <select id="getDept" resultMap="myDepts"> select d.dept_id,d.dept_name ,e.id,e.name,e.gender,e.email from dept d LEFT JOIN emp e ON d.dept_id = e.dept_id where d.dept_id = #{dept_id} </select>
关联的嵌套 Select 查询(分步查询):
同样的需求:查询一个部门中的多个员工
mapper中的接口:
//通过部门的id查询员工 public List<Emp> selectEmps(Integer dept_id); //通过部门id查询部门 public Dept selectDept(Integer dept_id);
DeptMapper.xml;
<!--分步查询--> <resultMap id="myDept" type="com.mybatis.bean.Dept"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result>
<!--property:Dept的属性名,column:传入的dept_id,select:查询的语句,fetchType有效值为 lazy 和 eager。 指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled,使用属性的值-> <collection property="emp" column="dept_id" select="com.mybatis.mapper.EmpMapper.selectEmpsStep"/> </resultMap> <select id="selectDept" resultMap="myDept"> SELECT dept_id,dept_name FROM dept WHERE dept_id = #{dept_id} </select>
EmpMapper.xml:
<select id="selectEmps" resultType="com.mybatis.bean.Emp"> SELECT id,name,gender,email FROM emp WHERE dept_id = #{dept_id} </select>
mybatis全局配置:
<setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/>
最终实现分步查询和延迟加载,当我们访问只dept时,就不会去执行emp的SQL语句
Dept dept = mapper.selectDept(10000);
System.out.println(dept.getDeptName());
System.out.println(dept.getEmp());
当我们去访问emp时,就会执行emp的SQL语句。
不过官方说分步查询和延迟加载会有性能问题