MyBatis 之 一對一、一對多、多對多


一、前言

自己用mybatis做項目的時候,有時候會對MyBatis 的一對一,一對多,以及多對多的關系映射,學習的時候沒有過深研究就草草了之了,因此會感到困惑,在此梳理下它的映射關系。

二、一對一 和 一對多

一對一和一對多比較簡單,可以在一起講。本次demo打算使用 用戶表(User),地址表(Address),汽車表(Car)來表述。即:一個用戶只有一個地址,兩者的關系是一對一;一對多的話,即一個用戶可以有多輛車,兩者的關系是一對多。

1.springboot項目搭建

1.1、項目配置

​ 本節的重點不在於springboot的pom.xml 導入了哪些包,mybatis如何配置,僅僅簡單說下:

pom.xml 中添加 : mybatis-spring-boot-starter 1.3.2mysql-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文件。三個表,創建三個控制層,以及也在其他各層創建其對應的接口類和接口實現類等等,在此略過。看下項目結構:

springboot-mybatis

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實體類 的每條信息。如圖:

image-20210313225925119

我們在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; 屬性;

mybatis-user-mapping

javaType 用來指定對象類型,在這指代的是address前面的Address類型,包括下面collection標簽中的javaType,都是實體類該屬性屬於什么類型。比如address前面是Address類型,cars前面是List數組類型,所以下面collection標簽中JavaType的值為java.util.ArrayList

mybatis-list-mapping

ofType指定的是 映射到list集合屬性中pojo的類型 。

這里需要注意的是: select方法中的sql語句,查詢的數據,表的id可能會相同,這樣查詢出的多條數據就無法映射到collection列表中,所以要在此改下查詢結果集的屬性,改成別名進行映射。

mapping-mybatis

三、多對多映射

我們使用常見的文章(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 中的代碼 :

many-to-many

同樣道理,當我們想要獲取一個分類下的文章列表時,和上面一樣。

many-to-many-

這兒也使用了左連接進行關聯映射查詢。

四、demo地址 :

鏈接:https://pan.baidu.com/s/1YF4Ys0OXaPW1uoRbdrMq3A 提取碼:p3ju


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM