本文主要講述mybatis的處理表與表之間的關係
一個部門可以有多個員工,但是一個員工只能屬於一個部門
1) Employee類的宣告如下
public class Employee { private Integer empId; private String empName; private Integer age; private String gender; private Department dept; public Employee() { } get和set()方法... @Override public String toString() { return "Employee{" + "empId=" + empId + ", empName='" + empName + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", dept=" + dept + '}'; } }
由於一個員工只能屬於一個部門,因此在Employee中才會有 private Department dept 成員變數。
2)Department類宣告如下
public class Department { private Integer deptId; private String deptName; private List<Employee> employees; public Department() { } get和set()方法... @Override public String toString() { return "Department{" + "deptId=" + deptId + ", deptName='" + deptName + '\'' + ", employees=" + employees + '}'; } }
由於一個部門可以有多個員工,因此在Department類中才會有 private List<Employee> employees 成員變數
這裡的多對一的關係是指:多個員工在一個部門,思考的角度是站在員工Employee類的。
當需要查詢單個員工資訊以及所在部門時,應該如何處理?
EmpMapper介面宣告如下
public interface EmpMapper { // 根據id查詢員工資訊 Employee selectEmpAndDept(@Param("id") int id); }
方式1:採用級聯的方式
EmpMapper.xml檔案宣告如下
<!--// 根據id查詢員工資訊 Employee selectEmpAndDept(@Param("id") int id);--> <!--使用: resultType="Employee"結果: Employee{empId=4, empName='趙六', age=24, gender='男', dept=null}--> <!--級聯--> <resultMap id="resultEmpAndDept1" type="Employee"> <id column="emp_id" property="empId" /> <result column="emp_name" property="empName" /> <result column="dept_id" property="dept.deptId" /> <result column="dept_name" property="dept.deptName" /> </resultMap>
<select id="selectEmpAndDept" resultMap="resultEmpAndDept1"> SELECT t_emp.*,t_dept.`dept_name` FROM t_emp,t_dept WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id} </select>
前面提過resultMap可以自定義對映名,下面闡述<resultMap>標籤
<!-- resultMap: id:resultMap標籤的唯一標識 type:返回型別 <id>:表t_emp的主鍵的欄位名 <result>:表t_emp的非主鍵的欄位名 其中 <result column="dept_id" property="dept.deptId" /> column:欄位名dept_id,property:實體類的屬性名dept.deptId 意義是將查詢到的部門資訊--封裝--》Department物件 --賦值--》Employee類中的dept成員變數 --> <resultMap id="resultEmpAndDept1" type="Employee"> <id column="emp_id" property="empId" /> <result column="emp_name" property="empName" /> <result column="dept_id" property="dept.deptId" /> <result column="dept_name" property="dept.deptName" /> </resultMap>
注意:<result column="dept_id" property="dept.deptId" />,是Employee類的成員物件dept . 屬性名
方式2:採用 association 標籤
EmpMapper.xml檔案宣告如下
<resultMap id="resultEmpAndDept2" type="Employee"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <!--association的 property:是需要處理對映關係的屬性名,如dept javaType:是設定要處理屬性的型別名稱--> <association property="dept" javaType="Department"> <id column="dept_id" property="deptId"></id> <id column="dept_name" property="deptName"></id> </association> </resultMap> <select id="selectEmpAndDept" resultMap="resultEmpAndDept2"> SELECT t_emp.*,t_dept.`dept_name` FROM t_emp,t_dept WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id} </select>
下面闡述<association>標籤 的內容
<!--association的 property:是需要處理對映關係的屬性名,如dept javaType:是設定要處理屬性的型別名稱--> <association property="dept" javaType="Department"> <id column="dept_id" property="deptId"></id> <id column="dept_name" property="deptName"></id> </association>
方式3:採用分步查詢
先根據員工編號,查詢員工資訊,在根據員工資訊中的部門編號,查詢相對應的部門資訊
因此,需要建立DeptMapper介面,DeptMapper介面的宣告如下
public interface DeptMapper { // 根據id查詢部門 Department selectDeptById(@Param("id") int id); }
DeptMapper.xml檔案宣告如下
<!--namespace繫結mapper的介面所在的包名.介面名--> <mapper namespace="com.hspedu.mapper.DeptMapper"> <!--// 根據id查詢部門 Department selectDeptById(@Param("id") int id);--> <select id="selectDeptById" resultType="Department"> select * from t_dept where dept_id = #{id} </select> </mapper>
EmpMapper.xml檔案宣告如下
<resultMap id="resultEmpAndDept3" type="Employee"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <!--association的 property:設定需要處理對映關係的屬性的屬性名 select:設定分步查詢的sql語句的唯一標識 column:將select標籤中查詢出的某一個欄位作為分步查詢的條件 fetchType:是否開啟延遲載入【針對某一個sql語句】eager立刻,lazy延遲 --> <association property="dept" fetchType="eager" select="com.hspedu.mapper.DeptMapper.selectDeptById" column="dept_id"> </association> </resultMap> <select id="selectEmpAndDeptThree" resultMap="resultEmpAndDept3" > select * from t_emp where emp_id = #{id} </select>
下面闡述 <association> 標籤的內容
<!--association的 property:設定需要處理對映關係的屬性的屬性名 select:設定分步查詢的sql語句的唯一標識 column:將select標籤中查詢出的某一個欄位作為分步查詢的條件 fetchType:在方法中是否開啟延遲載入【針對某一個sql語句】eager立刻,lazy延遲 --> <association property="dept" fetchType="eager" select="com.hspedu.mapper.DeptMapper.selectDeptById" column="dept_id"> </association>
注意:association標籤中的select的意義,
在t_emp表中查詢到的員工資訊欄位中的dept_id值作為引數,傳入到DeptMapper介面的selectDeptById()方法中,
在t_dept表中按照部門編號dept_id查詢相對應的部門資訊。
分步查詢 插入一個知識點:延遲載入
a> 引入延遲載入
當我們只是想查詢員工資訊的姓名時,例如
@Test // 查詢指定id的員工資訊 public void test02(){ Employee employee = mapper.selectEmpAndDept(4); System.out.println(employee.getEmpName()); }
如果沒有延遲載入的話,執行結果如下
DEBUG 02-04 15:37:05,646 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137) DEBUG 02-04 15:37:05,669 ====> Preparing: select * from t_dept where dept_id = ? (BaseJdbcLogger.java:137) DEBUG 02-04 15:37:05,669 ====> Parameters: 100(Integer) (BaseJdbcLogger.java:137) DEBUG 02-04 15:37:05,675 <==== Total: 1 (BaseJdbcLogger.java:137) DEBUG 02-04 15:37:05,677 <== Total: 1 (BaseJdbcLogger.java:137) 趙六
即執行了查詢員工資訊的sql語句,又執行了查詢部門資訊的sql語句,如何讓它不執行查詢部門資訊的sql語句呢?
b> 延遲載入的設定
在mybatis-config.xml檔案中新增如下setting標籤,引入延遲載入
<settings> <!--將MySQL中_對映為java的駝峰--> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 開啟延時載入【懶載入】--> <setting name="lazyLoadingEnabled" value="true"/> <!--強制載入所有的懶設定--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
並將<association fetchType="eager"> 的 fetchType = "lazy",即在執行該sql語句時,使用延遲載入,執行結果如下
DEBUG 02-04 15:42:26,231 ==> Preparing: select * from t_emp where emp_id = ? (BaseJdbcLogger.java:137) DEBUG 02-04 15:42:26,261 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137) DEBUG 02-04 15:42:26,322 <== Total: 1 (BaseJdbcLogger.java:137) 趙六
只執行了查詢員工資訊的sql語句,說明延遲載入有了效果。
c> 延遲載入總結:
引入延遲載入,在mybatis組態檔中新增setting標籤......【全域性 延遲載入】
如果對於某一個sql語句,不想使用延遲載入,則<association fetchType="eager"> 【區域性 不使用延遲載入】
根據傳入的emp_id在t_emp表中查詢員工資訊,員工資訊的欄位中包含有dept_id,然後依據dept_id,在t_dept表中查詢相應的部門資訊,
將部門資訊--反射-->Department類的物件--賦值-->Employee類的成員變數dept。
這裡的一對多是一個部門可以有多個員工,是在Department類角度考慮的。
按照部門編號查詢一個部門有多少員工?
DeptMapper介面宣告如下
public interface DeptMapper { // 查詢一個部門有多少員工 Department selectDeptAndEmp(@Param("id") int id); }
方式1:使用collection標籤
DeptMapper.xml檔案宣告如下
<!--// 查詢一個部門有多少員工 Department selectDeptAndEmp(@Param("id") int id);--> <resultMap id="resultDeptAndEmp1" type="Department"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> <collection property="employees" ofType="Employee"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age" ></result> <result column="gender" property="gender"></result> </collection> </resultMap> <select id="selectDeptAndEmp" resultMap="resultDeptAndEmp1"> SELECT t_emp.*,t_dept.* FROM t_emp,t_dept WHERE t_emp.`dept_id` = t_dept.`dept_id` and t_dept.dept_id = #{id} </select>
下面闡述collection標籤
<collection property="employees" ofType="Employee"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age" ></result> <result column="gender" property="gender"></result> </collection>
property:實體類的成員變數【屬性】,ofType:表示將查詢的結果--封裝-->實體類物件--裝入-->集合
方式2:分步查詢
第一步:在t_dept表中根據傳入的dept_id查詢部門資訊
第二步:在t_emp中根據第一步中得到的dept_id查詢員工資訊
EmpMapper介面的宣告如下
public interface EmpMapper { // 根據部門編號查詢員工資訊 List<Employee> selectEmployeesByDeptId(@Param("id") int id); }
EmpMapper.xml檔案宣告如下
<!-- // 根據部門編號查詢員工資訊 List<Employee> selectEmployeesByDeptId(@Param("id") int id);--> <resultMap id="resultEmployeesByDeptId" type="Employee"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> </resultMap> <select id="selectEmployeesByDeptId" resultMap="resultEmployeesByDeptId"> select * from t_emp where dept_id = #{id} </select>
DeptMapper.xml檔案宣告如下
<resultMap id="resultDeptAndEmp" type="Department"> <id column="dept_id" property="deptId"></id> <result column="dept_name" property="deptName"></result> <association property="employees" fetchType="lazy" select="com.hspedu.mapper.EmpMapper.selectEmployeesByDeptId" column="dept_id"></association> </resultMap> <select id="selectDeptAndEmpTwo" resultMap="resultDeptAndEmp"> select * from t_dept where dept_id = #{id} </select>
使用association標籤,
property:實體類需要對映處理的成員名【屬性】;
select:呼叫EmpMapper介面的 selectEmployeesByDeptId()方法,即 根據得到的部門資訊中的dept_id,在t_emp表中查詢該部門的所有員工資訊。
由dept_id在t_emp查詢的結果集--反射-->Employee物件--裝入-->Employee集合--賦值-->Department類的employees成員變數。