当前位置: 首页 > article >正文

<collection> 和 <association>的详细用法(附详细代码解析)

MyBatis 中的 <association><collection> 标签

在 MyBatis 中,<association><collection> 标签用于配置复杂查询的结果集关联映射,主要用于处理实体类之间的嵌套关系。二者的区别在于:

  • <association> 标签用于一对一的关系映射,比如实体类 A 中包含一个实体类 B 的对象。
  • <collection> 标签用于一对多的关系映射,比如实体类 A 中包含一个 B 类对象的集合。

示例:<association><collection> 标签的区别

我们以下面的场景为例:

  • 一个 User 实体类,它有一个 Address 实体类的属性(表示一对一关系)。
  • 一个 User 实体类,它有多个 Order 实体类的对象(表示一对多关系)。

数据库表结构

假设有三个表:useraddressorders,表结构如下:

user 表结构:
CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    address_id BIGINT
);
address 表结构:
CREATE TABLE address (
    id BIGINT PRIMARY KEY,
    city VARCHAR(50),
    street VARCHAR(100)
);
orders 表结构:
CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT,
    product_name VARCHAR(100),
    price DECIMAL(10, 2)
);

实体类定义

以下是 Java 实体类定义:

User 实体类:
public class User {
    private Long id;
    private String name;
    private int age;
    private Address address; // 一对一关系
    private List<Order> orders; // 一对多关系

    // getters and setters
}
Address 实体类:
public class Address {
    private Long id;
    private String city;
    private String street;

    // getters and setters
}
Order 实体类:
public class Order {
    private Long id;
    private Long userId;
    private String productName;
    private BigDecimal price;

    // getters and setters
}

MyBatis 映射配置

UserMapper.xml 配置

UserMapper.xml 中使用 <association><collection> 标签来映射复杂关系:

<mapper namespace="com.example.mapper.UserMapper">
    <!-- 查询用户及其地址和订单信息 -->
    <select id="getUserById" resultMap="userResultMap">
        SELECT
            u.id AS user_id, u.name, u.age,
            a.id AS address_id, a.city, a.street,
            o.id AS order_id, o.product_name, o.price
        FROM user u
        LEFT JOIN address a ON u.address_id = a.id
        LEFT JOIN orders o ON u.id = o.user_id
        WHERE u.id = #{id}
    </select>

    <!-- 用户结果映射 -->
    <resultMap id="userResultMap" type="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        
        <!-- 一对一映射 Address -->
        <association property="address" javaType="com.example.entity.Address" columnPrefix="address_" fetchType="lazy" select="com.example.mapper.AddressMapper.getAddressById">
            <id property="id" column="address_id"/>
            <result property="city" column="city"/>
            <result property="street" column="street"/>
        </association>

        <!-- 一对多映射 Orders -->
        <collection property="orders" ofType="com.example.entity.Order" columnPrefix="order_" fetchType="lazy">
            <id property="id" column="order_id"/>
            <result property="productName" column="product_name"/>
            <result property="price" column="price"/>
        </collection>
    </resultMap>
</mapper>
  • <association> 标签:用于映射 User 和 Address 之间的一对一关系,将 Address 的属性映射到 User 对象中的 address 属性上。

    • columnPrefix 属性:用于为关联对象的列指定前缀,以避免与其他表的列名冲突。
    • fetchType 属性:用于指定加载方式,lazy 表示懒加载,eager 表示立即加载。
    • select 属性:用于指定关联关系中需要调用的查询方法,这里可以指定一个 Mapper 方法(例如 com.example.mapper.AddressMapper.getAddressById),以实现更灵活的关联查询。
  • <collection> 标签:用于映射 User 和 Order 之间的一对多关系,将 Order 的列表映射到 User 对象中的 orders 属性上。

    • columnPrefix 属性:与 <association> 中的 columnPrefix 类似,用于避免列名冲突。
    • fetchType 属性:指定加载方式,支持懒加载和立即加载。

常用的高级属性与用法

除了上面提到的 <association><collection> 标签中使用的常见属性外,还有一些高级的标签和属性可以提高 MyBatis 的映射功能和灵活性:

  1. resultMap 标签中的 autoMapping 属性

    • autoMapping:自动映射列到属性,true 表示自动进行映射,false 表示不自动映射,可以用于减少手动配置的工作量。
    <resultMap id="userResultMap" type="com.example.entity.User" autoMapping="true">
        ...
    </resultMap>
    
  2. <constructor> 标签

    • <constructor> 标签用于在对象创建时通过构造函数传递参数。
    • 可以使用 <idArg><arg> 标签来指定构造函数参数的映射关系。
    <resultMap id="userResultMap" type="com.example.entity.User">
        <constructor>
            <idArg column="user_id" javaType="Long"/>
            <arg column="name" javaType="String"/>
            <arg column="age" javaType="int"/>
        </constructor>
        ...
    </resultMap>
    
  3. <discriminator> 标签

    • 用于处理多态对象的映射关系。可以根据某个字段的值来动态选择不同的子类映射。
    • 例如根据用户类型字段 user_type 来区分普通用户和管理员。
    <resultMap id="userResultMap" type="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="name" column="name"/>
        <discriminator javaType="String" column="user_type">
            <case value="ADMIN" resultType="com.example.entity.AdminUser"/>
            <case value="USER" resultType="com.example.entity.RegularUser"/>
        </discriminator>
    </resultMap>
    
  4. <collection><association>cascade 属性

    • cascade:指定在父对象操作时是否对关联对象进行级联操作,例如插入、更新和删除。MyBatis 不直接提供 cascade 的配置,但可以通过编程方式实现类似的级联操作。
  5. select 属性的动态关联

    • select 属性 可以使用动态参数,灵活地调用其他查询,特别是在需要根据不同条件关联查询的时候,能极大增强查询能力。

Mapper 接口

定义 UserMapper 接口用于数据库访问:

public interface UserMapper {
    User getUserById(Long id);
}

定义 AddressMapper 接口,用于单独查询 Address 数据:

public interface AddressMapper {
    Address getAddressById(Long id);
}

Service 层

在 Service 层通过注入 UserMapper 来调用查询方法:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.getUserById(id);
    }
}

Controller 层

在 Controller 层处理前端的请求,返回用户数据:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
}

前端返回的 JSON 数据

假设用户的 ID 为 1,数据库中的数据如下:

  • User 表中:{id: 1, name: "John", age: 30, address_id: 1}
  • Address 表中:{id: 1, city: "New York", street: "5th Avenue"}
  • Orders 表中有两条记录:
    • {id: 1, user_id: 1, product_name: "Laptop", price: 1200.00}
    • {id: 2, user_id: 1, product_name: "Smartphone", price: 800.00}

返回的 JSON 数据将会是:

{
  "id": 1,
  "name": "John",
  "age": 30,
  "address": {
    "id": 1,
    "city": "New York",
    "street": "5th Avenue"
  },
  "orders": [
    {
      "id": 1,
      "productName": "Laptop",
      "price": 1200.00
    },
    {
      "id": 2,
      "productName": "Smartphone",
      "price": 800.00
    }
  ]
}

总结

  • <association> 标签 用于一对一映射,将 Address 映射到 User 对象的 address 属性中,支持属性如 columnPrefixfetchTypeselect 来控制列前缀、加载方式和关联查询。
  • <collection> 标签 用于一对多映射,将 Order 列表映射到 User 对象的 orders 属性中,类似地支持 columnPrefixfetchType 等属性。
  • <constructor> 标签 可以用于通过构造函数创建对象。
  • <discriminator> 标签 适用于多态映射,根据某些字段动态选择子类映射。

这些高级标签和属性在 MyBatis 的复杂查询和结果集映射中非常有用,能有效地将关系型数据库的数据转换为 Java 对象,从而简化开发工作。


http://www.kler.cn/a/374057.html

相关文章:

  • 缓存使用的最佳实践,自定义缓存工具类
  • ros中launch文件学习(3)
  • 如何在短时间内入门并掌握深度学习?
  • 【安全解决方案】深入解析:如何通过CDN获取用户真实IP地址
  • 3D Gaussian Splatting代码详解(二):模型构建
  • 巨好看的登录注册界面源码
  • vue3+pinia实现状态管理和持久化存储
  • 工业网络监控中的IP保护与软件授权革新
  • [LeetCode] 494. 目标和
  • ffmpeg 提取mp4文件中的音频文件并保存
  • 重塑社区治理:王鹏谈Vitalik Buterin的去中心化理念
  • 前端如何解决浏览器input输入框密码自动填充的问题
  • 配置DDNS结合光猫路由器实现外网映射
  • Docker 60个常用命令汇总
  • springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)
  • 丢失有一段时间时的数据可以找回吗?可以!
  • Rust 知识的 20 道练习题和详细解答
  • 【JVM】——GC垃圾回收机制(图解通俗易懂)
  • nginx 路径匹配,关于“/“对规则的影响
  • 多厂商的实现不同vlan间通信
  • LLM速览篇【241-270】
  • 高效网络自动化:Python在网络基础中的应用
  • [论文精读]LoRA: Low-Rank Adaptation of Large Language Models
  • 【初阶数据结构与算法】新的旅程之时间复杂度和空间复杂度
  • 学Linux的第五天
  • 如何在被 DDoS 攻击时更换 IP 地址