Mybatis 学习之路其四:级联
一、前言
我參加工作的初期,對于mybatis還不太了解,開發的過程更多是參考公司大牛的代碼,然后依樣畫葫蘆。當時設計到 A 類里包含 B 類,然后查詢 A 類相關信息(包含B類)的時候,我當時還不懂級聯,使用的是一個笨方法,重新建了一個類,這個類包含了 A 類和 B 類的所有信息。這是一個非常笨的方法。事實上,利用 mybatis 的級聯功能,能夠很簡單的查詢一對一,和一對多的關系。
二、一對一關系查詢
?在我們使用的 mysql 的測試數據中個,我們選出一個一對一的關系進行測試,比如:員工表,和員工-部門號表。前者是員工的基本信息,我們前面使用了很多次,后面是員工號和部門號的對應關系。現在,我們要在獲取員工基本信息的時候,把員工的部門號一并獲取過來。
首先,修改下員工的信息的 javabean:
1 import java.util.Date; 2 import java.util.List; 3 import salary.model.SalaryModel; 4 public class EmployeeModel { 5 private int empNo; 6 private Date birthDate; 7 private String firstName; 8 private String lastName; 9 private String gender; 10 private Date hireDate; 11 private String deptNo; 12 private List<SalaryModel> salaries = null; 13 public int getEmpNo() { 14 return empNo; 15 } 16 public void setEmpNo(int empNo) { 17 this.empNo = empNo; 18 } 19 public Date getBirth_date() { 20 return birthDate; 21 } 22 public void setBirth_date(Date birth_date) { 23 this.birthDate = birth_date; 24 } 25 public String getFirstName() { 26 return firstName; 27 } 28 public void setFirstName(String firstName) { 29 this.firstName = firstName; 30 } 31 public String getLastName() { 32 return lastName; 33 } 34 public void setLastName(String lastName) { 35 this.lastName = lastName; 36 } 37 public String getGender() { 38 return gender; 39 } 40 public void setGender(String gender) { 41 this.gender = gender; 42 } 43 public Date getHireDate() { 44 return hireDate; 45 } 46 public void setHireDate(Date hireDate) { 47 this.hireDate = hireDate; 48 } 49 50 public String toString() { 51 StringBuilder strBuilder = new StringBuilder(); 52 strBuilder.append("empNo : "); 53 strBuilder.append(empNo); 54 strBuilder.append(" firstName : "); 55 strBuilder.append(firstName); 56 strBuilder.append(" lastName : "); 57 strBuilder.append(lastName); 58 strBuilder.append(" deptNo : "); 59 strBuilder.append(deptNo); 60 strBuilder.append("\nsalaries:\n"); 61 if(salaries != null) { 62 for(SalaryModel index : salaries) { 63 strBuilder.append(index.toString()); 64 strBuilder.append("\n"); 65 } 66 } 67 return strBuilder.toString(); 68 } 69 public List<SalaryModel> getSalaries() { 70 return salaries; 71 } 72 public void setSalaries(List<SalaryModel> salaries) { 73 this.salaries = salaries; 74 } 75 public String getDeptNo() { 76 return deptNo; 77 } 78 public void setDeptNo(String deptNo) { 79 this.deptNo = deptNo; 80 } 81 }為了后面測試一對多關系,我提前在 bean 里加了存儲工資信息的 List。
然后針對員工-部門號表,我們需要建立對應的 bean,dao,mapper:
bean:
1 import java.util.Date; 2 3 public class DeptManager { 4 private int empNo; 5 private String deptNo; 6 private Date fromDate; 7 private Date toDate; 8 public int getEmpNo() { 9 return empNo; 10 } 11 public void setEmpNo(int empNo) { 12 this.empNo = empNo; 13 } 14 public String getDeptNo() { 15 return deptNo; 16 } 17 public void setDeptNo(String deptNo) { 18 this.deptNo = deptNo; 19 } 20 public Date getFromDate() { 21 return fromDate; 22 } 23 public void setFromDate(Date fromDate) { 24 this.fromDate = fromDate; 25 } 26 public Date getToDate() { 27 return toDate; 28 } 29 public void setToDate(Date toDate) { 30 this.toDate = toDate; 31 } 32 33 }dao:
public interface DeptManagerDao {String getDeptNoByEmpNo(int empNo); }mapper:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace = "employee.dao.DeptManagerDao"><resultMap type="employee.model.DeptManager" id="deptManager"><result column = "emp_no" property = "empNo"/><result column = "dept_no" property = "deptNo"/><result column = "from_date" property = "fromDate"/><result column = "to_date" property = "toDate"/> </resultMap><select id = "getDeptNoByEmpNo" parameterType = "int" resultType = "java.lang.String">select dept_no from dept_manager where emp_no = #{empNo}</select></mapper>然后記得在 mybatis-config 里加載這個新建的 mapper:
<mapper resource="employee/mapper/DeptManagerMapper.xml"/>到目前為止,沒有任何特殊的地方,也沒有關于一對一的任何操作,接下來是重點,首先,我們再 employee 的 resultMap 里加入我們新建的 dempNo,但是加入的方式和其他不同:
<association property = "deptNo" column = "emp_no" select = "employee.dao.DeptManagerDao.getDeptNoByEmpNo"/>首先,它的元素不在是 result,而是 association,association 這里我們用到了 3 個屬性:
property 和 result 元素一樣,對應了 javaBean 里的屬性;
column 對應了數據庫里的列,注意,這個列不是去和 column 對應的,而是作為參數去傳給其他 sql 的,傳給誰?;
select 決定了參數的傳遞對象。
我們先看,這樣配置之后,我們再獲取 employee 信息的時候發生了什么。
運行測試代碼:
1 SqlSession sqlSession = SqlSessionFactoryUtils.openSqlSession(); 2 EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class); 3 EmployeeModel model = employeeDao.getEmployeeByEmpNo(111784); 4 System.out.print(model);然后 log4j 的輸出是:
[DEBUG] 2018-10-01 17:17:44,817: [Thread-main : org.apache.ibatis.datasource.pooled.PooledDataSource] Created connection 936906727. [DEBUG] 2018-10-01 17:17:44,817: [Thread-main : org.apache.ibatis.transaction.jdbc.JdbcTransaction] Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@37d80fe7] [DEBUG] 2018-10-01 17:17:44,821: [Thread-main : employee.dao.EmployeeDao.getEmployeeByEmpNo] ==> Preparing: select emp_no,first_name,birth_date,last_name,gender,hire_date from employees where emp_no = ? [DEBUG] 2018-10-01 17:17:44,865: [Thread-main : employee.dao.EmployeeDao.getEmployeeByEmpNo] ==> Parameters: 111784(Integer) [DEBUG] 2018-10-01 17:17:44,911: [Thread-main : employee.dao.DeptManagerDao.getDeptNoByEmpNo] ====> Preparing: select dept_no from dept_manager where emp_no = ? [DEBUG] 2018-10-01 17:17:44,911: [Thread-main : employee.dao.DeptManagerDao.getDeptNoByEmpNo] ====> Parameters: 111784(Integer) [DEBUG] 2018-10-01 17:17:44,914: [Thread-main : employee.dao.DeptManagerDao.getDeptNoByEmpNo] <==== Total: 1我們發現,在執行了 employee.mapper 里的根據 emp_no 查詢員工信息之后,mybatis 又自動執行了一條 sql,這條 sql 就是我們再 select 屬性里指定的方法,而這個方法是有一個參數的,系統吧 column 指定的列的值傳遞了過去,然后將這條 sql 獲取的值,裝填到 employee 的 deptNo 屬性中去。
System.out.println 的結果是:empNo : 111784 firstName : Marjo lastName : Giarratana deptNo : d009 (截取了關鍵部分)。
可以猜出,這條 sql 的發起點是在 resultmap 里。
光是這樣,還不足以體現 mybatis 級聯的強大,畢竟上述的例子,只要一個 left join 就能搞定,無需這么麻煩。因為,我們需要從其他表獲取的不過一個字段而已,但是如果我們獲取的是一個對象,就非常麻煩了,又或者是一個對象的集合。下面的一對多的級聯就是一個對象的集合。
三、一對多關聯查詢
這次我們用工資表和員工表關聯,每個月都會發工資,所以員工表和工資表必定能是一對多關聯。?
還是先把 工資表相關的準備工作做好
bean:
1 import java.util.Date; 2 3 public class SalaryModel { 4 private int empNo; 5 private int salary; 6 private Date fromDate; 7 private Date toDate; 8 9 public int getEmpNo() { 10 return empNo; 11 } 12 13 public void setEmpNo(int empNo) { 14 this.empNo = empNo; 15 } 16 17 public int getSalary() { 18 return salary; 19 } 20 21 public void setSalary(int salary) { 22 this.salary = salary; 23 } 24 25 public Date getFromDate() { 26 return fromDate; 27 } 28 29 public void setFromDate(Date fromDate) { 30 this.fromDate = fromDate; 31 } 32 33 public Date getToDate() { 34 return toDate; 35 } 36 37 public void setToDate(Date toDate) { 38 this.toDate = toDate; 39 } 40 41 public String toString() { 42 return "empNo: " + empNo + " salary: " + salary + " from : " + fromDate + " to : " + toDate + "\n"; 43 } 44 }dao:
import java.util.List;import salary.model.SalaryModel;public interface SalaryDao {List<SalaryModel> getSalaryByEmpNo(int empNo); }mapper:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="salary.dao.SalaryDao"> 6 <resultMap type = "salary.model.SalaryModel" id = "salary"> 7 <result column = "emp_no" property = "empNo"/> 8 <result column = "salary" property = "salary"/> 9 <result column = "from_date" property = "fromDate"/> 10 <result column = "to_date" property = "toDate"/> 11 </resultMap> 12 <sql id = "salaryCols"> 13 emp_no,salary,from_date,to_date 14 </sql> 15 <select id = "getSalaryByEmpNo" resultMap = "salary"> 16 select <include refid = "salaryCols" /> from salaries where emp_no = #{empNo} 17 </select> 18 </mapper>mybatis-config 加載:
<mapper resource="salary/mapper/SalaryMapper.xml"/>下面是重點,這次我們還是在 resultMap 里做點手腳,但是不再是 association,一對多關聯時,應該使用 collection:
<collection property = "salaries" column = "emp_no"select = "salary.dao.SalaryDao.getSalaryByEmpNo" />屬性作用和 association 一致,然后我們運行測試程序:
輸出:
empNo : 111784 firstName : Marjo lastName : Giarratana deptNo : d009 salaries: empNo: 111784 salary: 40000 from : Fri Feb 12 08:00:00 CST 1988 to : Sat Feb 11 08:00:00 CST 1989empNo: 111784 salary: 41189 from : Sat Feb 11 08:00:00 CST 1989 to : Sun Feb 11 08:00:00 CST 1990empNo: 111784 salary: 44026 from : Sun Feb 11 08:00:00 CST 1990 to : Mon Feb 11 08:00:00 CST 1991empNo: 111784 salary: 48315 from : Mon Feb 11 08:00:00 CST 1991 to : Tue Feb 11 08:00:00 CST 1992empNo: 111784 salary: 48079 from : Tue Feb 11 08:00:00 CST 1992 to : Wed Feb 10 08:00:00 CST 1993empNo: 111784 salary: 48181 from : Wed Feb 10 08:00:00 CST 1993 to : Thu Feb 10 08:00:00 CST 1994empNo: 111784 salary: 48273 from : Thu Feb 10 08:00:00 CST 1994 to : Fri Feb 10 08:00:00 CST 1995empNo: 111784 salary: 49770 from : Fri Feb 10 08:00:00 CST 1995 to : Sat Feb 10 08:00:00 CST 1996empNo: 111784 salary: 51900 from : Sat Feb 10 08:00:00 CST 1996 to : Sun Feb 09 08:00:00 CST 1997empNo: 111784 salary: 52121 from : Sun Feb 09 08:00:00 CST 1997 to : Mon Feb 09 08:00:00 CST 1998empNo: 111784 salary: 54187 from : Mon Feb 09 08:00:00 CST 1998 to : Tue Feb 09 08:00:00 CST 1999empNo: 111784 salary: 54138 from : Tue Feb 09 08:00:00 CST 1999 to : Wed Feb 09 08:00:00 CST 2000empNo: 111784 salary: 54183 from : Wed Feb 09 08:00:00 CST 2000 to : Thu Feb 08 08:00:00 CST 2001empNo: 111784 salary: 57946 from : Thu Feb 08 08:00:00 CST 2001 to : Fri Feb 08 08:00:00 CST 2002empNo: 111784 salary: 58189 from : Fri Feb 08 08:00:00 CST 2002 to : Fri Jan 01 08:00:00 CST 9999其道理和 association 是一致的,這里我們成功的將獲取到的工資信息裝填到了 employee 的屬性 salaries(List)中。
四、mybatis 小結
到目前為止,mybatis 的基礎功能已經差不多結束了,mybatis 還有很多強大的功能,比如插件在以后再繼續學習。本著由簡到難的方式,mybatis 暫時告一段落,接下來是 SSM 框架的 spring 部分。
轉載于:https://www.cnblogs.com/JiKio/p/9728806.html
總結
以上是生活随笔為你收集整理的Mybatis 学习之路其四:级联的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL查询缓存总结
- 下一篇: 深圳美大和浙江美大是一家吗 两家各论各的