mybatis入門篇(六):Mybatis高級查詢

一、ResultMap的association與collection association與collection功能相似,區別是一對一與一對多,這裏以association爲例。java

首先說明一下需求:經過員工ID獲取員工信息,同時獲取員工的角色,涉及到了員工信息表、角色表、還有兩者的關聯表。最簡單的作法是寫一個SQL語句,語句裏寫了三個表,互相關聯進行查詢,但這種方式存在問題:一、SQL語句不易維護 二、複用性不強 三、我只想獲取用戶的信息,不用角色信息時,查詢了多餘的信息,徒增消耗。sql

解決辦法:一、對每一個實體都定義一個基礎的ResultMap,根據須要繼承基礎ResultMap再添加自定義的屬性 二、在ResultMap中使用association或者collection進行關聯查詢 三、使用延遲加載,須要角色信息時再去查詢。mybatis

實際操做過程:app

新建實體類User和Role測試

import java.util.Date;
public class Role {
    private Long id;
    private String roleName;
    private Integer enabled;
    private Long createBy;
    private Date createTime;
    private Long updateBy;
    private Date updateTime;

    ...
    getter和setter就省略了
    ...
}
import java.util.Date;
import java.util.List;
public class User {
    private Long id;
    private String userName;
    private String userPassword;
    private String userPhone;
    private String userEmail;
    private Date createTime;
    private Date updateTime;
    private byte[] headImg;
    private Role role;

    ...
    getter和setter省略了
    ...
}

而後編寫Mapper.xmlfetch

首先先編寫其中的字段映射部分BaseResultMap。spa

UserMapper.xmlrest

<resultMap id="BaseResultMap" type="com.forest.owl.entity.User">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="user_password" jdbcType="VARCHAR" property="userPassword" />
    <result column="user_phone" jdbcType="VARCHAR" property="userPhone" />
    <result column="user_email" jdbcType="VARCHAR" property="userEmail" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
    <result column="head_img" jdbcType="LONGVARBINARY" property="headImg" />
</resultMap>

RoleMapper.xmlcode

<resultMap id="BaseResultMap" type="com.forest.owl.entity.Role">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="role_name" jdbcType="VARCHAR" property="roleName" />
    <result column="enabled" jdbcType="INTEGER" property="enabled" />
    <result column="create_by" jdbcType="BIGINT" property="createBy" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_by" jdbcType="BIGINT" property="updateBy" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>

編寫RoleMapper.xml獲取Role的接口和XMLxml

import com.forest.owl.entity.Role;
public interface RoleMapper {
    Role selectByPrimaryKey(Long id);
}

RoleMapper.xml

<select id="selectByPrimaryKey" resultMap="BaseResultMap">
    select id, role_name, enabled, create_by, create_time, update_by, update_time
    from role
    where id = #{id,jdbcType=BIGINT}
</select>

而後編寫UserMapper.xml

<resultMap id="UserAndRole" extends="BaseResultMap" type="com.forest.owl.entity.User">
    <association property="role" fetchType="lazy" column="{id=role_id}" select="com.forest.owl.mapper.RoleMapper.selectByPrimaryKey"/>
</resultMap>

<select id="selectUsersById" resultMap="UserAndRole">
    SELECT u.*, ur.role_id
    FROM user u
    INNER JOIN user_role ur on ur.user_id=u.id
    WHERE u.id=#{id}
</select>

能夠看到,UserMapper的SQL語句中少了role表,這樣SQL語句就簡潔多了。須要注意,association中的fetchType=「lazy」選項,當執行getRole()的時候,纔回去查詢角色信息加載到查詢結果中。若是用戶仍是須要在觸發某個方法時加載所有數據,則能夠配置mybatis的配置選項lazyLoadTriggerMethods,按需加載。

對於3.4.1 及以前版本的mybatis用戶,還須要配置mybatis-config.xml的一個選項:

<setting name="aggressiveLazyLoading" value="false"/>

測試:

@Test
public void UserMapperTest(){
    SqlSession sqlSession = getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.selectUsersById((long) 2);
    System.out.println(userList.size());
    System.out.println("--------getRole---------");
    System.out.println(userList.get(0).getRole());
}

執行結果

collection的代碼

import java.util.Date;
import java.util.List;
public class User {
    private Long id;
    private String userName;
    private String userPassword;
    private String userPhone;
    private String userEmail;
    private Date createTime;
    private Date updateTime;
    private byte[] headImg;
    private List<Role> roleList;
    ...
    getter和setter省略
    ...
}
<?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.forest.owl.mapper.UserMapper">
  <resultMap id="BaseResultMap" type="com.forest.owl.entity.User">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="user_password" jdbcType="VARCHAR" property="userPassword" />
    <result column="user_phone" jdbcType="VARCHAR" property="userPhone" />
    <result column="user_email" jdbcType="VARCHAR" property="userEmail" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
    <result column="head_img" jdbcType="LONGVARBINARY" property="headImg" />
  </resultMap>

  <resultMap id="UserAndRole" extends="BaseResultMap" type="com.forest.owl.entity.User">
    <collection property="roleList" columnPrefix="role_" fetchType="lazy"
                resultMap="com.forest.owl.mapper.RoleMapper.BaseResultMap">
      <id property="id" column="id"/>
      <result column="role_name" property="roleName" />
      <result column="enabled" property="enabled" />
      <result column="create_by" property="createBy" />
      <result column="create_time" property="createTime" />
      <result column="update_by" property="updateBy" />
      <result column="update_time" property="updateTime" />
    </collection>
  </resultMap>

  <select id="selectUsersById" resultMap="UserAndRole">
    SELECT u.*,
    r.id role_id,
    r.role_name role_role_name,
    r.enabled role_enabled,
    r.create_by role_create_by,
    r.create_time role_create_time,
    r.update_by role_update_by,
    r.update_time role_update_time
    FROM user u
    INNER JOIN user_role ur on ur.user_id=u.id
    INNER JOIN role r on r.id=ur.role_id
    WHERE u.id=#{id}
  </select>
</mapper>

UserMapper接口

import com.forest.owl.entity.User;
public interface UserMapper {
    User selectUsersById(Long id);
}
@Test
public void UserMapperTest(){
    SqlSession sqlSession = getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.selectUsersById((long) 2);
    System.out.println(user.getRoleList().get(0).getRoleName());
    System.out.println(user.getRoleList().get(1).getRoleName());
}