一、前言
自己用mybatis
做項目的時候,有時候會對MyBatis 的一對一,一對多,以及多對多的關系映射,學習的時候沒有過深研究就草草了之了,因此會感到困惑,在此梳理下它的映射關系。
二、一對一 和 一對多
一對一和一對多比較簡單,可以在一起講。本次demo打算使用 用戶表(User),地址表(Address),汽車表(Car)來表述。即:一個用戶只有一個地址,兩者的關系是一對一;一對多的話,即一個用戶可以有多輛車,兩者的關系是一對多。
1.springboot項目搭建
1.1、項目配置
本節的重點不在於springboot的pom.xml 導入了哪些包,mybatis如何配置,僅僅簡單說下:
pom.xml 中添加 : mybatis-spring-boot-starter 1.3.2
和 mysql-connector-java
兩個。
application.yml 配置:
server:
port: 8080
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapping/*Mapper.xml
type-aliases-package: com.example.entity
#showSql
logging:
level:
com:
example:
mapper : debug
1.2、項目結構
本次demo會創建controller、service、service.imp、mapper、entity等包,以及在resources文件夾下創建mapping文件夾存放mybatis的xml文件。三個表,創建三個控制層,以及也在其他各層創建其對應的接口類和接口實現類等等,在此略過。看下項目結構:
1.3 實體類代碼(無get和set方法,記得自己添加)
public class User {
private Long id;
private String nick_name ; // 用戶昵稱
private Address address; //地址信息,和用戶是一對一的關系
private List<Car> cars; //用戶擁有的車,和用戶是一對多的關系
//TODO:無參構造,有參構造,get和set方法
}
//----------------------------------------------
public class Address implements Serializable {
private Long id; // ID
private String province; //省市
private String city; // 城市
//TODO:無參構造,有參構造,get和set方法
}
//----------------------------------------------
public class Car implements Serializable {
private Long id; // id
private String color; // 顏色
private String name; // 名稱
private User user ; // 用戶
//TODO:無參構造,有參構造,get和set方法
}
1.4、UserMapper.xml 演示一對一、一對多
我們以用戶為例,通過用戶id ,獲取用戶的id,nick_name,地址的id、省市、城市;(一對一)以及用戶所擁有的的車輛cars列表,
列表里是Car實體類 的每條信息。如圖:
我們在UserController 編寫 getOneAddress()
方法,粘貼下控制層方法,直接到UserMapper.xml 中
@Autowired
private AddressService addressService ;
@RequestMapping("getOneAddress")
public Address getOneAddress(Long id){
Address address = addressService.getOneAddress(id);
return address ;
}
UserMapper.xml
代碼 :
<resultMap id="BaseMap" type="com.dzbiao.springbootmybatis.entity.User">
<id property="id" column="id" />
<result property="nick_name" column="nick_name" />
<!--一對一-->
<association property="address" javaType="com.dzbiao.springbootmybatis.entity.Address" >
<id property="id" column="id" />
<result property="city" column="city" />
<result property="province" column="province" />
</association>
<!--一對多-->
<!--JavaType和ofType都是用來指定對象類型的,但是JavaType是用來指定pojo中屬性的類型,而ofType指定的是 映射到list集合屬性中pojo的類型 -->
<collection property="cars" ofType="com.dzbiao.springbootmybatis.entity.Car" javaType="java.util.ArrayList">
<id property="id" column="c_id" />
<result property="color" column="color" />
<result property="name" column="name" />
</collection>
</resultMap>
<select id="getOneUser" resultMap="BaseMap">
select user.*,address.* ,car.id as c_id ,car.color,car.name,car.user_id
from user,address,car
where user.id = #{id} and user.address_id = address.id and user.id = car.user_id
</select>
上述代碼解釋一下 :
首先我們id = "getOneUser"的select方法的結果映射時BaseMap,我們通過association標簽和另一張表Address進行關聯映射,property的值即是User表中 的 private Address address;
屬性;
javaType
用來指定對象類型,在這指代的是address前面的Address類型,包括下面collection
標簽中的javaType
,都是實體類該屬性屬於什么類型。比如address前面是Address
類型,cars前面是List數組類型,所以下面collection
標簽中JavaType
的值為java.util.ArrayList
。
而ofType
指定的是 映射到list集合屬性中pojo的類型 。
這里需要注意的是: select方法中的sql語句,查詢的數據,表的id可能會相同,這樣查詢出的多條數據就無法映射到collection列表中,所以要在此改下查詢結果集的屬性,改成別名進行映射。
三、多對多映射
我們使用常見的文章(article
)和分類(category
)進行多對多講解。一篇文章有多個分類,一個分類下擁有多篇文章。
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `article` VALUES (1, 'Java基礎', '這是一個java的示例文章');
INSERT INTO `article` VALUES (2, 'Python學習', 'Python學習示例');
INSERT INTO `article` VALUES (3, 'Springboot學習', 'springboot學習案例');
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `category` VALUES (1, 'Java');
INSERT INTO `category` VALUES (2, 'Python ');
INSERT INTO `category` VALUES (3, 'HTML');
INSERT INTO `category` VALUES (4, 'JavaScript');
INSERT INTO `category` VALUES (5, 'Linux');
INSERT INTO `category` VALUES (6, 'CSS');
INSERT INTO `category` VALUES (7, 'Go');
-- ----------------------------
-- 中間表
-- ----------------------------
CREATE TABLE `article_category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`article_id` int(11) NULL DEFAULT NULL,
`category_id` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of article_category
-- ----------------------------
INSERT INTO `article_category` VALUES (1, 1, 1);
INSERT INTO `article_category` VALUES (2, 1, 3);
INSERT INTO `article_category` VALUES (3, 1, 4);
INSERT INTO `article_category` VALUES (4, 1, 6);
INSERT INTO `article_category` VALUES (5, 2, 2);
INSERT INTO `article_category` VALUES (6, 2, NULL);
INSERT INTO `article_category` VALUES (7, 2, 4);
INSERT INTO `article_category` VALUES (8, 2, 6);
INSERT INTO `article_category` VALUES (9, 3, 1);
實體類 Article 和Category:
public class Article implements Serializable {
private Integer id ; // 文章ID
private String title ; // 文章標題
private String content ; // 文章內容
private List<Category> categories ; // 分類列表
}
public class Category implements Serializable {
private Integer id ;// 分類ID
private String name ; // 分類名稱
private List<Article> articles ; // 文章列表
}
多對多映射,可以看成兩個一對多。一個文章實體類有一個分類的列表,而分類的實體類則也有一個文章列表。
直接看 ArticleMapper.xml
中的代碼 :
同樣道理,當我們想要獲取一個分類下的文章列表時,和上面一樣。
這兒也使用了左連接進行關聯映射查詢。
四、demo地址 :
鏈接:https://pan.baidu.com/s/1YF4Ys0OXaPW1uoRbdrMq3A 提取碼:p3ju