MyBatis實(shí)現(xiàn)高級(jí)映射的示例代碼
1 association 和 collection 介紹
在之前的 SQL 映射文件中提及了 resultMap 元素的 association 和 collection 標(biāo)簽,這兩個(gè)標(biāo)簽是用來(lái)關(guān)聯(lián)查詢的,它們的屬性幾乎一致,以下是對(duì)它們屬性的描述,紅色標(biāo)注的是常用屬性。
| 屬性 | 描述 |
|---|---|
| property | 實(shí)體類屬性名 |
| column | 數(shù)據(jù)庫(kù)字段名或者其別名 |
| javaType | 實(shí)體類屬性的 Java 類型 |
| jdbcType | 數(shù)據(jù)庫(kù)列的數(shù)據(jù)類型 |
| ofType | 指定關(guān)聯(lián)對(duì)象的類型。它通常用于泛型類型的情況,以確保正確的類型轉(zhuǎn)換 |
| select | 指定一個(gè)子查詢,用于加載關(guān)聯(lián)的對(duì)象 |
| fetchType | 用于控制加載策略,比如立即加載還是延遲加載。常見(jiàn)的取值有 lazy(延遲加載)和 eager(立即加載) |
| resultMap | 引用預(yù)定義的結(jié)果映射,以便更靈活地配置關(guān)聯(lián)對(duì)象的映射規(guī)則 |
| resultSet | 指定結(jié)果集的名稱,以便在多結(jié)果集的情況下進(jìn)行區(qū)分 |
| autoMapping | 是否自動(dòng)映射所有列到目標(biāo)對(duì)象的屬性上。默認(rèn)為 true,表示自動(dòng)映射;設(shè)置為 false 則表示不自動(dòng)映射 |
| columnPrefix | 當(dāng)使用內(nèi)連接查詢時(shí),這個(gè)屬性可以用來(lái)指定前綴,以區(qū)分關(guān)聯(lián)表的列名 |
| foreignColumn | 指定外鍵對(duì)應(yīng)的列名 |
| notNullColumn | 指定一個(gè)列名,只有當(dāng)該列的值不為 null 時(shí),才會(huì)執(zhí)行關(guān)聯(lián)查詢 |
| typeHandler | 自定義的類型處理器 |
2 案例分析
以典型的 員工 (Employee) 和部門 (Department) 為例
- 一個(gè)員工只能在一個(gè)部門:Employee -> Department(一對(duì)一)
- 一個(gè)部門可以包含多個(gè)員工:Department -> Employee(一對(duì)多)
以用戶 (User) 和角色 (Role) 為例,兩者成了一個(gè)雙向的一對(duì)多,從而變成了多對(duì)多,不做介紹
- 一個(gè)用戶可以擁有多個(gè)角色:User -> Role(一對(duì)多)
- 一個(gè)角色可以賦予多個(gè)用戶:Role -> User(一對(duì)多)
表 department 和 表 employee
# 創(chuàng)建 department 表
drop table if exists department;
create table department(
department_id int(11) primary key auto_increment, #主鍵,自增
department_name varchar(255)
)charset=utf8;
# 插入數(shù)據(jù)
insert into department(department_name) values
('開(kāi)發(fā)部'),
('人力資源部'),
('市場(chǎng)營(yíng)銷部'),
('財(cái)務(wù)部'),
('行政部'),
('監(jiān)察部'),
('客服服務(wù)部');
# 創(chuàng)建 employee 表
drop table if exists employee;
create table employee(
employee_id int(11) primary key auto_increment, #主鍵,自增
employee_name varchar(255),
employee_age int(11),
employee_sex char(32),
employee_email varchar(255),
employee_address varchar(255),
department_id int(11)
)charset=utf8;
# 插入數(shù)據(jù)
insert into employee values
(1, '唐浩榮', 23, 1, '15477259875@163.com', '中國(guó)上海浦東區(qū)', 1),
(2, '黃飛鴻', 32, 1, '86547547@qq.com', '大清廣東', 2),
(3, '十三姨', 18, 0, '520520520@gmail.com', '大清廣東', 3),
(4, '納蘭元述', 28, 1, '545627858@qq.com', '大清京師', 5),
(5, '梁寬', 31, 1, '8795124578@qq.com', '大清廣東', 7),
(6, '蔡徐坤', 20, 0, '4257895124@gmail.com', '四川成都', 4),
(7, '楊超越', 21, 0, '8746821252@qq.com', '中國(guó)北京', 7),
(8, '馬保國(guó)', 66, 1, '6666666666@qq.com', '廣東深圳', 6),
(9, '馬牛逼', 45, 1, 'asdfg45678@163.com', '湖北武漢', 3);

3 一對(duì)一關(guān)聯(lián)和一對(duì)多關(guān)聯(lián)
工程目錄

Department 類
public class Department {
//部門id
private Integer deptId;
//部門名稱
private String deptName;
//部門有哪些員工
private List<Employee> employees;
// Getter、Setter、toString 方法省略
}Employee 類
public class Employee {
//員工id
private Integer empId;
//員工名稱
private String empName;
//員工年齡
private Integer empAge;
//員工性別
private Integer empSex;
//員工郵箱
private String empEmail;
//員工地址
private String empAddress;
//員工所屬部門,和部門表構(gòu)成一對(duì)一的關(guān)系,一個(gè)員工只能在一個(gè)部門
private Department department;
// Getter、Setter、toString 方法省略
}創(chuàng)建 DepartmentMapper
public interface DepartmentMapper {
//查詢所有數(shù)據(jù)
@Select("select * from department")
@Results(id = "deptMap1", value = {
@Result(property = "deptId", column = "department_id"),
@Result(property = "deptName", column = "department_name"),
// 一對(duì)多關(guān)聯(lián)對(duì)象
// 根據(jù) department_id 來(lái)比較
@Result(property = "employees", column = "department_id",
many = @Many(select = "com.mapper.EmployeeMapper.selectEmpByDeptId"))
})
List<Department> selectAll();
// 根據(jù) id 查找部門
@Select("select * from department where department_id = #{id}")
@Results(id = "deptMap2", value = {
@Result(property = "deptId", column = "department_id"),
@Result(property = "deptName", column = "department_name")
})
Department findDepartmentById(int id);
}創(chuàng)建 EmployeeMapper
public interface EmployeeMapper {
//查詢所有數(shù)據(jù)
@Select("select * from employee")
@Results(id = "empMap1", value = {
@Result(property = "empId", column = "employee_id", id = true),
@Result(property = "empName", column = "employee_name"),
@Result(property = "empAge", column = "employee_age"),
@Result(property = "empSex", column = "employee_sex"),
@Result(property = "empEmail", column = "employee_email"),
@Result(property = "empAddress", column = "employee_address"),
// 一對(duì)一關(guān)聯(lián)對(duì)象
// 根據(jù) department_id 來(lái)比較
@Result(property = "department", column = "department_id",
one = @One(select = "com.mapper.DepartmentMapper.findDepartmentById"))}
)
List<Employee> selectAll();
//根據(jù)員工id查詢數(shù)據(jù)
@Select("select * from employee where employee_id = #{id}")
@ResultMap("empMap1")
Employee selectEmpByEmpId(@Param("id") int empId);
// 根據(jù) department_id 查詢數(shù)據(jù)
@Select("select * from employee where department_id = #{id}")
@ResultMap("empMap1")
Employee selectEmpByDeptId(@Param("id") int deptId);
}log4j.properties
log4j.rootLogger=DEBUG, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.java.sql.ResultSet=INFO log4j.logger.org.apache=INFO log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
mysql.properties
url=jdbc:mysql://localhost:3306/study?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC name=root password=123456 driver=com.mysql.cj.jdbc.Driver
MyBatis 配置文件 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 通過(guò)properties標(biāo)簽,讀取java配置文件的內(nèi)容 -->
<properties resource="mysql.properties" />
<!-- 配置環(huán)境.-->
<environments default="development">
<environment id="development">
<!--配置事務(wù)的類型-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 元素使用標(biāo)準(zhǔn)的 JDBC 數(shù)據(jù)源接口來(lái)配置 JDBC 連接對(duì)象源 -->
<dataSource type="POOLED">
<!--配置連接數(shù)據(jù)庫(kù)的4個(gè)基本信息-->
<property name="url" value="${url}" />
<property name="username" value="${name}" />
<property name="password" value="${password}" />
<property name="driver" value="${driver}" />
</dataSource>
</environment>
</environments>
<!--通過(guò)包 package 引入 SQL 映射文件-->
<mappers>
<package name="com.mapper"/>
</mappers>
</configuration>創(chuàng)建 EmployeeTest 測(cè)試類
public class EmployeeTest {
//定義 SqlSession
SqlSession sqlSession = null;
//定義 EmployeeMapper 對(duì)象
private EmployeeMapper mapper = null;
@Before
public void getSqlSession() throws IOException {
//加載 mybatis 全局配置文件 Resources
// 原 InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//創(chuàng)建 SqlSessionFactory 對(duì)象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//根據(jù) sqlSessionFactory 產(chǎn)生 session
sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建Mapper接口的的代理對(duì)象,getMapper方法底層會(huì)通過(guò)動(dòng)態(tài)代理生成 EmployeeMapper 的代理實(shí)現(xiàn)類
mapper = sqlSession.getMapper(EmployeeMapper.class);
}
//查詢所有員工數(shù)據(jù)
@Test
public void testSelectAll() {
List<Employee> listEmployee = mapper.selectAll();
for (Employee employee : listEmployee) {
System.out.println(employee);
}
sqlSession.close();
}
//根據(jù)員工 id 查詢數(shù)據(jù)
@Test
public void testSelectById() {
Employee employee = mapper.selectEmpByEmpId(1);
System.out.println(employee);
sqlSession.close();
}
}測(cè)試結(jié)果
查詢所有員工數(shù)據(jù),包括員工所在部門(一個(gè)員工屬于一個(gè)部門)

創(chuàng)建 DepartmentTest 測(cè)試類
public class DepartmentTest {
//定義 SqlSession
SqlSession sqlSession = null;
//定義 DepartmentMapper 對(duì)象
private DepartmentMapper mapper = null;
@Before
public void getSqlSession() throws IOException {
//加載 mybatis 全局配置文件 Resources
// 原 InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//創(chuàng)建 SqlSessionFactory 對(duì)象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//根據(jù) sqlSessionFactory 產(chǎn)生 session
sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建Mapper接口的的代理對(duì)象,getMapper方法底層會(huì)通過(guò)動(dòng)態(tài)代理生成 DepartmentMapper 的代理實(shí)現(xiàn)類
mapper = sqlSession.getMapper(DepartmentMapper.class);
}
//查詢所有部門數(shù)據(jù)
@Test
public void testSelectAll() {
List<Department> listDepartment = mapper.selectAll();
for (Department department : listDepartment) {
System.out.println(department);
}
sqlSession.close();
}
//根據(jù)部門 id 查詢 數(shù)據(jù)
@Test
public void testSelectById() {
Department department = mapper.findDepartmentById(1);
System.out.println(department);
sqlSession.close();
}
}測(cè)試結(jié)果
查詢所有部門信息,包括該部門有哪些員工(一個(gè)部門有多個(gè)員工)

4 參考文檔
Mybatis3詳解(八)----高級(jí)映射之一對(duì)一映射
Mybatis3詳解(九)----高級(jí)映射之一對(duì)多映射
到此這篇關(guān)于MyBatis實(shí)現(xiàn)高級(jí)映射的示例代碼的文章就介紹到這了,更多相關(guān)MyBatis 高級(jí)映射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis高級(jí)映射學(xué)習(xí)教程
- MyBatis高級(jí)映射和查詢緩存
- Mybatis高級(jí)映射、動(dòng)態(tài)SQL及獲得自增主鍵的解析
- mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼
- 基于mybatis高級(jí)映射多對(duì)多查詢的實(shí)現(xiàn)
- javaMybatis映射屬性,高級(jí)映射詳解
- 解析Mybatis延遲加載問(wèn)題
- MyBatis延遲加載與立即加載案例教程
- MyBatis高級(jí)映射ResultMap解決屬性問(wèn)題
- Mybatis中的延遲加載,以及原理分析
- 詳解MyBatis延遲加載是如何實(shí)現(xiàn)的
- MyBatis高級(jí)映射及延遲加載的實(shí)現(xiàn)
相關(guān)文章
提升網(wǎng)絡(luò)請(qǐng)求穩(wěn)定性HttpClient的重試機(jī)制深入理解
這篇文章主要為大家介紹了提升網(wǎng)絡(luò)請(qǐng)求穩(wěn)定性HttpClient的重試機(jī)制深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Java關(guān)鍵字synchronized基本使用詳解
這篇文章主要給大家介紹了關(guān)于Java關(guān)鍵字synchronized基本使用的相關(guān)資料,synchronized可以用來(lái)同步靜態(tài)和非靜態(tài)方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
Windows7下的Java運(yùn)行環(huán)境搭建過(guò)程圖解
這篇文章主要介紹了Windows7下的Java運(yùn)行環(huán)境搭建過(guò)程圖解,需要的朋友可以參考下2014-04-04
Java中內(nèi)部類使用方法實(shí)戰(zhàn)案例分析
這篇文章主要介紹了Java中內(nèi)部類使用方法,結(jié)合具體案例形式分析了Java內(nèi)部類原理、調(diào)用方法及相關(guān)使用注意事項(xiàng),需要的朋友可以參考下2019-09-09
java實(shí)現(xiàn)后臺(tái)數(shù)據(jù)顯示在前端
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)后臺(tái)數(shù)據(jù)顯示在前端,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
Android應(yīng)用開(kāi)發(fā)之將SQLite和APK一起打包的方法
這篇文章主要介紹了Android應(yīng)用開(kāi)發(fā)之將SQLite和APK一起打包的方法,文章時(shí)間較早,盡管現(xiàn)在開(kāi)發(fā)環(huán)境已大都遷移至Android Studio上,但打包原理依然相同,需要的朋友可以參考下2015-08-08
Java中內(nèi)存異常StackOverflowError與OutOfMemoryError詳解
這篇文章主要介紹了 Java中內(nèi)存異常StackOverflowError與OutOfMemoryError詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03

