SQL 映射文件有很少的幾個頂級元素(按照它們應該被定義的順序):
- cache – 給定命名空間的緩存配置。
- cache-ref – 其他命名空間緩存配置的引用。
- resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
parameterMap – 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這里不會記錄。- sql – 可被其他語句引用的可重用語句塊。
- insert – 映射插入語句
- update – 映射更新語句
- delete – 映射刪除語句
- select – 映射查詢語句
1.基本增刪改查
定義接口
public interface employeeMapper {
public employee getEmployeeById(int id);
public int addEmp(employee employee);
public boolean editEmp(employee employee);
public int delEmp(int id);
}
EmplyoeeMapper.xml
<?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">
<!--
namespace:命名空間,指定為接口的全類名
-->
<!--<mapper namespace="com.tancom.tangge.Mapper.employeeMapperpper">-->
<mapper namespace="com.tangge.Mapper.employeeMapper">
<!--接口方式:
id:接口方法名 ,resultType:返回類型
-->
<select id="getEmployeeById" resultType="com.tangge.model.employee">
select `id`, `last_name` lastName, `gender`, `email` from tbl_employee where id = #{id}
</select>
<!--插入 parameterType:參數類型(可以省略 -->
<insert id="addEmp" parameterType="com.tangge.model.employee">
insert into `db_mybatis`.`tbl_employee` ( `last_name`, `gender`, `email`)
values (#{lastName}, #{gender}, #{email} );
</insert>
<!--更新-->
<update id="editEmp">
update tbl_employee set last_name = #{lastName},email=#{email},gender=#{gender}
where id =#{id}
</update>
<!--刪除-->
<delete id="delEmp">
DELETE FROM tbl_employee where id =#{id}
</delete>
</mapper>
---->【測試】:
/**
* 1.mybatis 允許直接定義下列返回值
* Boolean/Long/Integer
* 2.手動提交數據
*/
//插入
public static void insertTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
//獲取 SqlSession,能直接執行已經映射的SQL語句
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
//employee employee = new employee("jerry","fne@xwf.com",'0');
employee employee = new employee("lily", "lily@xwf.com", '1');
//1.插入數據
int rows = mapper.addEmp(employee);
System.out.println("影響行數:" + rows);
//2.手動提交數據
session.commit();
} finally {
session.close();
}
}
//修改
public static void updateTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
//獲取 SqlSession,能直接執行已經映射的SQL語句
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
employee employee = new employee(4,"jerry","fne@xwf.com",'1');
//1.修改數據
boolean rows = mapper.editEmp(employee);
System.out.println("修改+是否成功:" + rows);
//2.手動提交數據
session.commit();
} finally {
session.close();
}
}
//刪除
public static void delTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
//獲取 SqlSession,能直接執行已經映射的SQL語句
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
//1.刪除數據
int rows = mapper.delEmp(4);
System.out.println("影響行數:" + rows);
//2.手動提交數據
session.commit();
} finally {
session.close();
}
}
2.獲取自增主鍵值
2.1 有自增功能數據庫(mysql,sqlserver)
Insert, Update, Delete 's Attributes
屬性 | 描述 |
---|---|
useGeneratedKeys |
(僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵 (比如:像 MySQL 和 SQL Server 這樣的關系數據庫管理系統的自動遞增字段),默認值:false。 |
keyProperty |
(僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設置它的鍵值, 默認:unset。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
<!--
mybatis獲取自增主鍵,和JDBC一樣,利用statement.getGeneratedKeys()
- useGeneratedKeys="true" 使用自增主鍵
- keyProperty:指定對應的主鍵屬性,將這個值賦給 javabean 的哪個屬性
-->
<insert id="addEmp" parameterType="com.tangge.model.employee"
useGeneratedKeys="true" keyProperty="id">
insert into `db_mybatis`.`tbl_employee` ( `last_name`, `gender`, `email`)
values (#{lastName}, #{gender}, #{email} );
</insert>
---->【測試】:
//插入
public static void insertTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
//獲取 SqlSession,能直接執行已經映射的SQL語句
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
//employee employee = new employee("jerry","fne@xwf.com",'0');
employee employee = new employee("lily", "lily@xwf.com", '1');
//1.插入數據
int rows = mapper.addEmp(employee);
System.out.println("影響行數:" + rows);
System.out.println("添加的員工ID:" + employee.getId());
//2.手動提交數據
session.commit();
} finally {
session.close();
}
}
這里 employee.getId()
獲取值
2.1 沒有自增功能數據庫(oracle)
oracle 不支持自增,使用序列
<!--oracle插入-->
<insert id="addEmpByOracle">
<!--
keyProperty:查出的主鍵值賦給 javabean 的哪個屬性
order="BEFORE":當前SQL在插入SQL之前執行
resultType:返回值類型
-->
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
<!--查詢主鍵的SQL-->
SELECT EMPLOYEES_SEQ.nextval FROM dual
</selectKey>
<!--oracle主鍵從序列中拿到-->
insert into employees ( employeeID, `last_name`, `gender`, `email`)
values (${id}, #{lastName}, #{gender}, #{email} );
</insert>
3.參數處理
3.1 單個參數
不做特殊處理。
#{參數}
:取出參數值
3.2 多個參數(不推薦)
多個參數會被封裝成一個 map
。
#{}
就是從map中獲取指定的key。
- key:param1...param2,或有參數的索引也可以
- value:傳入的值
---->【測試】:
新定義一個接口,傳入兩個參數。
public employee getEmployeeParam(int id,String lastName);
以 paramN 傳入key。
<select id="getEmployeeParam" resultType="com.tangge.model.employee">
select * from tbl_employee where id = #{param1} and last_name = #{param2}
</select>
3.3 命名參數(推薦)
明確指定封裝參數時 map 的 key:@Param("id")
多個參數會被封裝為一個 map。
key:使用 @Param 注解指定的值
value:參數值
---->【測試】:
public employee getEmployeeParam(@Param("id") int id,@Param("lastName") String lastName);
@Param 傳入key
<select id="getEmployeeParam" resultType="com.tangge.model.employee">
<!--select * from tbl_employee where id = #{param1} and last_name = #{param2}-->
select * from tbl_employee where id = #{id} and last_name = #{lastName}
</select>
3.4 POJO
如果多個參數正好是我們業務邏輯的數據模型,我們可以直接傳 POJO
#{屬性名}
:取出傳入 pojo 的值
3.5 Map
如果多個參數不是我們業務邏輯的數據模型,沒有對應的 POJO,我們也可以傳入Map
#{key}
: 取出 map 的值
---->【測試】:
<select id="getEmployeeMap" resultType="com.tangge.model.employee">
select * from tbl_employee where id = #{id} and last_name = #{lastName}
</select>
定義接口
public interface employeeMapper {
public employee getEmployeeMap(Map<String,Object> map);
...
}
測試方法:
public static void selectMapTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
//獲取 SqlSession,能直接執行已經映射的SQL語句我
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("lastName", "tom");
employee employee = mapper.getEmployeeMap(map);
System.out.println(employee);
} finally {
session.close();
}
}
3.6 TO
如果多個參數不是我們業務邏輯的數據模型,又經常要使用,推薦寫一個 TO(Transfer Object)數據傳輸對象
Page{
int size;
int index;
}
3.7 List/Collection/Array
把List或數組封裝在Map中
Key:
- Collection ==> collection
- List ==> list
- 數組 ==> array
例子:
public void getEmpId(List<Integer> ids);
取值:第一個id的值:#{list[0]}
3.8 參數值的獲取 (#{}與${}的區別)
#{}
:可以獲取map中的值或者pojo對象屬性的值;
${}
:可以獲取map中的值或者pojo對象屬性的值;
select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
區別:
#{}:是以預編譯的形式,將參數設置到sql語句中;PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去參數的值都應該去使用#{};
原生jdbc不支持占位符的地方我們就可以使用${}進行取值
比如分表、排序。。。;按照年份分表拆分
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
---->【測試】:
這里${tableName}是預編譯
<select id="getEmployeeMap" resultType="com.tangge.model.employee">
<!--select * from tbl_employee where id = ? and last_name =?-->
select * from ${tableName} where id = #{id} and last_name = #{lastName}
</select>
JAVA
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("lastName", "tom");
map.put("tableName", "tbl_employee");
employee employee = mapper.getEmployeeMap(map);
3.9 #{}:更豐富的用法:
- 規定參數的一些規則:
javaType、 jdbcType、 mode(存儲過程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未來准備支持的功能); jdbcType
通常需要在某種特定的條件下被設置:-
在我們數據為null的時候,有些數據庫可能不能識別mybatis對null的默認處理。比如Oracle(報錯);
JdbcType OTHER:無效的類型;
因為mybatis對所有的null都映射的是原生Jdbc的OTHER類型,oracle不能正確處理; -
由於全局配置中:jdbcTypeForNull=OTHER;oracle不支持;兩種辦法
1、#{email,jdbcType=OTHER};insert into employees ( employeeID, `last_name`, `gender`, `email`) values (#{id}, #{lastName}, #{gender}, #{email,jdbcType=NULL} );
2、jdbcTypeForNull=NULL
<settings> <setting name="jdbcTypeForNull" value="NULL"/> </settings>
-
4.Select
4.1 返回 List
接口
public List<employee> getEmployeesByLastNameLike(String lastName);
resultType:如果返回一個集合,只要集合中元素的類型
配置
<!--返回List集合:
resultType:如果返回一個集合,只要集合中元素的類型
-->
<select id="getEmployeesByLastNameLike" resultType="com.tangge.model.employee">
select * from tbl_employee where last_name LIKE #{lastName}
</select>
---->【測試】:
public static void selectListTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
List<employee> employees = mapper.getEmployeesByLastNameLike("%i%");
System.out.println(employees);
} finally {
session.close();
}
}
結果:
[com.tangge.model.employee{id=1, lastName='null', email='tom@guigu.com', gender=0}, com.tangge.model.employee{id=5, lastName='null', email='lily@xwf.com', gender=1}]
4.2 返回 Map
接口
//返回一條:記錄的map,key 就是列名,value 就是對應的值
public Map<String,Object> getEmpByIdReturnMap(int id);
//返回多條:封裝一個Map時,key 是這條記錄的主鍵,value 是記錄封裝后的 javabean
//@MapKey("last_name") --> key可以得到 last_name 的 字段
@MapKey("id")
public Map<Integer,employee> getEmpByLastNameReturnMap(String lastName);
配置
resultType 的 Map 別名 map
<!--返回一條:Map集合:
resultType:如果返回一個集合,只要集合中元素的類型
-->
<select id="getEmpByIdReturnMap" resultType="map">
select * from tbl_employee where id = #{id}
</select>
<!--返回多條:Map集合:
resultType:如果返回一個集合,只要集合中元素的類型
-->
<select id="getEmpByLastNameReturnMap" resultType="map">
select * from tbl_employee where last_name LIKE #{lastName}
</select>
---->【測試】:
//返回多條 Map
public static void selectEmpByLastNameReturnMapTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
Map<Integer ,employee> employees = mapper.getEmpByLastNameReturnMap("%i%");
System.out.println(employees);
//結果:
// {1={gender=0, last_name=tomi, id=1, email=tom@guigu.com}, 5={gender=1, last_name=lily, id=5, email=lily@xwf.com}}
} finally {
session.close();
}
}
//返回一條Map
public static void selectEmpByIdReturnMapTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapper mapper = session.getMapper(employeeMapper.class);
Map<String ,Object> employees = mapper.getEmpByIdReturnMap(1);
System.out.println(employees);
//結果:
//{gender=0, last_name=tomi, id=1, email=tom@guigu.com}
} finally {
session.close();
}
}
5.resultMap 結果集
resultMap 元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBC ResultSets 數據提取代碼中解放出來, 並在一些情形下允許你做一些 JDBC 不支持的事情。 實際上,在對復雜語句進行聯合映射的時候,它很可能可以代替數千行的同等功能的代碼。 ResultMap 的設計思想是,簡單的語句不需要明確的結果映射,而復雜一點的語句只需要描述它們的關系就行了。
屬性:
- id 當前命名空間中的一個唯一標識,用於標識一個result map.
- type 類的完全限定名, 或者一個類型別名 (內置的別名可以參考上面的表格).
- autoMapping 如果設置這個屬性,MyBatis將會為這個ResultMap開啟或者關閉自動映射。這個屬性會覆蓋全局的屬性 autoMappingBehavior。默認值為:unset。
子屬性:
- constructor - 用於在實例化類時,注入結果到構造方法中
- idArg - ID 參數;標記出作為 ID 的結果可以幫助提高整體性能
- arg - 將被注入到構造方法的一個普通結果
- id – 一個 ID 結果;標記出作為 ID 的結果可以幫助提高整體性能
- result – 注入到字段或 JavaBean 屬性的普通結果
- association – 一個復雜類型的關聯;許多結果將包裝成這種類型
- 嵌套結果映射 – 關聯可以指定為一個 resultMap 元素,或者引用一個
- collection – 一個復雜類型的集合
- 嵌套結果映射 – 集合可以指定為一個 resultMap 元素,或者引用一個
- discriminator – 使用結果值來決定使用哪個 resultMap
- case – 基於某些值的結果映射
- 嵌套結果映射 – 一個 case 也是一個映射它本身的結果,因此可以包含很多相 同的元素,或者它可以參照一個外部的 resultMap。
- case – 基於某些值的結果映射
5.1 自定義結果映射規則
定義接口
public interface employeeMapperResultMap {
public employee getEmployeeById(int id);
}
XML配置
<?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.tangge.Mapper.employeeMapperResultMap">
<!--
resultMap:
自定義javabean規則,外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多復雜映射的情形都能迎刃而解。
使用 resultMap 或 resultType,但不能同時使用。
- id:唯一id
- type:自定義java規則
-->
<resultMap id="MyEmp" type="com.tangge.model.employee">
<!--
id:指定主鍵封裝規則
column:指定哪一列,
property:對應javabean屬性
-->
<id column="id" property="id"></id>
<!--result:其他列的規則-->
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
</resultMap>
<select id="getEmployeeById" resultMap="MyEmp">
select * from tbl_employee where id = #{id}
</select>
</mapper>
---->【測試】:
public static void selectListTest() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
employee employees = mapper.getEmployeeById(1);
System.out.println(employees);
} finally {
session.close();
}
}
結果:
com.tangge.model.employee{id=1, lastName='tomi', email='tom@guigu.com', gender=0}
5.2 關聯查詢
5.2.1 級聯屬性封裝
tbl_employee 員工表,增加一個字段 dept_id
再增加一個部門表 tbl_dept
public class employee {
private int id;
private String lastName;
private String email;
private char gender;
private deptment dept; //部門
...
}
部門類
public class deptment {
private int departmentId;
private String departmentName;
...
}
配置 Mapper
<!--1.級聯屬性-->
<resultMap id="EmpAndDept" type="com.tangge.model.employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<!--級聯屬性
deptment:在employee類中定義 privdeptment dept;
-->
<result column="dept_id" property="dept.departmentId"></result>
<result column="dept_name" property="dept.departmentName"></result>
</resultMap>
<!--
查詢結果:
id last_name gender email dept_id dept_name
-->
<select id="getEmpAndDept" resultMap="EmpAndDept">
SELECT a.*,b.`dept_name` FROM tbl_employee a
JOIN tbl_dept b
ON a.dept_id=b.id
WHERE a.`id`=#{id}
</select>
---->【測試】:
public static void selectEmpAndDept() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
employee employees = mapper.getEmpAndDept(1);
System.out.println(employees);
/**
* 結果:
* employee{id=1, lastName='tomi', email='tom@guigu.com', gender=0,
* deptment=deptment{departmentId=1, departmentName='技術部'}}
*/
} finally {
session.close();
}
}
5.2.2 association 嵌套查詢
association + property + javaType
association – 一個復雜類型的關聯;許多結果將包裝成這種類型
Mapper配置
<!--2.association定義聯合對象-->
<resultMap id="EmpAndDept2" type="com.tangge.model.employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<!--
association:指定聯合的對象
- property="dept":指定哪個屬性是聯合對象
- javaType:指定類型
-->
<association property="dept" javaType="com.tangge.model.deptment">
<id column="dept_id" property="departmentId"></id>
<result column="dept_name" property="departmentName"></result>
</association>
</resultMap>
<!--
查詢結果:
id last_name gender email dept_id dept_name
-->
<select id="getEmpAndDept" resultMap="EmpAndDept2">
SELECT a.*,b.`dept_name` FROM tbl_employee a
JOIN tbl_dept b
ON a.dept_id=b.id
WHERE a.`id`=#{id}
</select>
結果:
employee{id=1, lastName='tomi', email='null', gender= , dept=deptment{departmentId=1, departmentName='技術部'}}
5.2.3 association 分步查詢
association + select + column
定義部門接口, 獲取部門的方法getDeptbyId
package com.tangge.Mapper;
import com.tangge.model.deptment;
public interface IdeptmentMapper {
public deptment getDeptbyId(int id);
}
創建XML
<?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.tangge.Mapper.IdeptmentMapper">
<select id="getDeptbyId" resultType="com.tangge.model.deptment">
select id,dept_name departmentName from tbl_dept where id = #{id}
</select>
</mapper>
使用分步查詢
<!--
3.使用association分步查詢:
3.1 按照員工id查詢員工信息
3.2 根據員工的dept_id查詢tbl_dept
3.3 把部門設置到員工中
-->
<resultMap id="MyEmpbyStep" type="com.tangge.model.employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<!--
association:定義關聯對象的封裝規則
- select:表名當前屬性調用select指定的方法
- column:指定講哪一列值傳給方法
-->
<association property="dept"
select="com.tangge.Mapper.IdeptmentMapper.getDeptbyId"
column="dept_id">
</association>
</resultMap>
<!--getEmpAndDeptByStep-->
<select id="getEmpAndDeptByStep" resultMap="MyEmpbyStep">
select * from tbl_employee where id = #{id}
</select>
---->【測試】:
public static void selectEmpAndDeptStep() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
employee employees = mapper.getEmpAndDeptByStep(1);
System.out.println(employees);
} finally {
session.close();
}
}
這里有個錯誤:蛋疼了1小時
---->【報錯】:
Caused by: java.lang.IllegalArgumentException:
Mapped Statements collection does not contain value for com.tangge.Mapper.IdeptmentMapper.getDeptbyId
為什么TM沒定義。查百度都沒用
后來想起貌似沒有給IdeptmentMapper.xml
注冊?????
<mapper resource="com/tangge/Mapper/IdeptmentMapper.xml"/>
ok了。
5.2.4 分步查詢&延遲加載
lazyLoadingEnabled (默認false):延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。 特定關聯關系中可通過設置 fetchType屬性來覆蓋該項的開關狀態。
aggressiveLazyLoading (默認true):當開啟時,任何方法的調用都會加載該對象的所有屬性。否則,每個屬性會按需加載(參考 lazyLoadTriggerMethods).
lazyLoadTriggerMethods :指定哪個對象的方法觸發一次延遲加載。
https://www.cnblogs.com/tangge/p/9518532.html#t1
<settings>
<!--顯示指定每個我們需要更改的值,即使他是默認的。防止版本更迭帶來的問題-->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
<!--<setting name="mapUnderscoreToCamelCase" value="true"></setting>-->
</settings>
---->【報錯】:
IDEA Cannot enable lazy loading because CGLIB is not available
原因是因為少了cglib.jar
,而cglib.jar有引入了asm.jar
,所以,這兩個jar包都需要導入。然后再次編譯測試就可以了。
public static void selectEmpAndDeptStep() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
employeeMapperResultMap mapper = session.getMapper(employeeMapperResultMap.class);
employee employees = mapper.getEmpAndDeptByStep(1);
// System.out.println(employees.getEmail());
System.out.println(employees);
/**
* (1)System.out.println(employees.getEmail());
* 只運行:select * from tbl_employee where id = 1
*
* (2)System.out.println(employees);
* 同時運行:
* 1.select * from tbl_employee where id = 1
* 2.select id,dept_name departmentName from tbl_dept where id = 1
*/
} finally {
session.close();
}
}
5.2.5 collection定義關聯集合封裝規則
collection – 一個復雜類型的集合
嵌套結果映射 – 集合可以指定為一個 resultMap 元素,或者引用一個
先新增字段,查詢部門下的所有員工。private List<employee> employees;
public class deptment {
private int departmentId;
private String departmentName;
private List<employee> employees; //新增:部門下的所有員工
@Override
public String toString() {
return "deptment{" +
"departmentId=" + departmentId +
", departmentName='" + departmentName + '\'' +
", employees=" + employees +
'}';
}
}
接口
public interface IdeptmentMapper {
public deptment getDeptbyId(int id);
//這個,deptment下定義List<employee> 定義collection,
public deptment getDeptbyIdCollection(int id);
}
定義XML
<resultMap id="deptCollection" type="com.tangge.model.deptment">
<id column="dept_id" property="departmentId"></id>
<result column="dept_name" property="departmentName"></result>
<!--
collection定義關聯的集合屬性.
property:指定變量,這里List<employee> employees
ofType:指定集合類型
-->
<collection property="employees" ofType="com.tangge.model.employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
</collection>
</resultMap>
<select id="getDeptbyIdCollection" resultMap="deptCollection">
SELECT a.*,b.`dept_name` FROM tbl_employee a
JOIN tbl_dept b
ON a.dept_id=b.id
WHERE b.`id`=#{id}
</select>
---->【測試】:
public static void selectDeptbyIdCollection() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IdeptmentMapper mapper = session.getMapper(IdeptmentMapper.class);
deptment deptment = mapper.getDeptbyIdCollection(1);
System.out.println(deptment);
} finally {
session.close();
}
}
/**
* 結果:
* deptment{departmentId=1, departmentName='技術部',
* employees=[employee{id=1, lastName='tomi', email='tom@guigu.com', gender= , dept=null},
* employee{id=6, lastName='wew', email='wewe@qq.com', gender= , dept=null}]}
*/
5.2.6 collection分步查詢
1.先查部門
2.再查部門下員工
定義部門接口 deptment getDeptbyIdCollectionByStep(int id);
public interface IdeptmentMapper {
public deptment getDeptbyId(int id);
//deptment下定義List<employee> 定義collection,
public deptment getDeptbyIdCollection(int id);
//分步collection定義:1.先查部門
public deptment getDeptbyIdCollectionByStep(int id);
}
查詢部門Mapper映射
<resultMap id="deptCollectionByStep" type="com.tangge.model.deptment">
<id column="id" property="departmentId"></id>
<result column="dept_name" property="departmentName"></result>
<collection property="employees"
select="com.tangge.Mapper.employeeMapperResultMap.getEmployeesBydeptId"
column="id">
</collection>
</resultMap>
<!--public deptment getDeptbyIdCollectionByStep(int id);-->
<select id="getDeptbyIdCollectionByStep" resultMap="deptCollectionByStep">
select id,dept_name departmentName from tbl_dept where id = #{id}
</select>
collection.select
需要員工新增接口List<employee> getEmployeesBydeptId(int id)
public interface employeeMapperResultMap {
public employee getEmployeeById(int id);
//聯合查詢
public employee getEmpAndDept(int id);
//分步查詢
public employee getEmpAndDeptByStep(int id);
//collection:分步查詢2
public List<employee> getEmployeesBydeptId(int id);
}
員工的Mapper映射
<!--collection:分步2:再查詢部門下的所有員工-->
<select id="getEmployeesBydeptId" resultType="com.tangge.model.employee">
select * from tbl_employee where dept_id = #{id}
</select>
---->【測試】:
public static void selectDeptbyIdCollectionByStep() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IdeptmentMapper mapper = session.getMapper(IdeptmentMapper.class);
deptment deptment = mapper.getDeptbyIdCollectionByStep(1);
System.out.println(deptment);
} finally {
session.close();
}
}
5.2.7 collection擴展:多列值&fetchType
fetchType:有效值為 lazy(延遲)和eager(立即)。
<resultMap id="deptCollectionByStep" type="com.tangge.model.deptment">
<id column="id" property="departmentId"></id>
<result column="dept_name" property="departmentName"></result>
<!--collection
- select:表名當前屬性調用select指定的方法
- column:傳入的值,多值傳輸封裝為Map傳遞:
{key1=column1,key2=column2,..}
- fetchType:有效值為 lazy和eager。 如果使用了,它將取代全局配置參數lazyLoadingEnabled。
-->
<collection property="employees"
select="com.tangge.Mapper.employeeMapperResultMap.getEmployeesBydeptId"
column="{x_deptid=id}" fetchType="lazy">
</collection>
</resultMap>
5.2.8 discriminator 鑒別器
(場景需求):
判斷性別:
女生:查部門
男生:lastName 賦值給 email
<!--
(場景需求):
判斷性別:
女生:查部門
男生:lastName 賦值給 email
-->
<resultMap id="MyEmpDis" type="com.tangge.model.employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<!--
discriminator:
- column:指定判定的列
- javaType:列值對應javabean的類型
-->
<discriminator javaType="string" column="gender">
<!--男生 resultType:指定封裝結果類型,不能缺少。 -->
<case value="0" resultType="com.tangge.model.employee">
<result column="last_name" property="email"></result>
</case>
<!--女生-->
<case value="1" resultType="com.tangge.model.employee">
<association property="dept" javaType="com.tangge.model.deptment">
<id column="dept_id" property="departmentId"></id>
<result column="dept_name" property="departmentName"></result>
</association>
</case>
</discriminator>
</resultMap>
<!--getEmpAndDeptByStep-->
<select id="getEmpAndDeptByStep" resultMap="MyEmpDis">
select * from tbl_employee where id = #{id}
</select>
---->【測試】:
如果是女生(id = 5):
employee{id=5, lastName='lily', email='null', gender=1, dept=deptment{departmentId=2, departmentName='null', employees=null}}
如果是男生(id = 1):
employee{id=1, lastName='tomi', email='tomi', gender=0, dept=null}