Mybatis多表查询!建议收藏!

在MyBatis中,<association><collection>是两个重要的元素,它们用于处理对象之间的关联关系,特别是在处理一对多(如订单和订单项)和多对一(如用户和部门)等关系时。以下是这两个元素的简要总结:

<association>

<association>元素用于处理“一对一”和“多对一”的关系。它用于将另一个表(或查询)的结果映射到一个复杂类型的属性上。

属性说明

  • property:指定映射到哪个Java对象的属性。
  • javaType:指定该属性的Java类型。
  • column:指定数据库中的哪一列用于作为外键。
  • select:指定一个用于加载关联对象的子查询ID。当使用懒加载时,这个属性特别有用。
  • fetchType:可选,指定加载策略(默认为eager,即预加载;也可以设置为lazy,即懒加载)。

示例

<resultMap id="userResultMap" type="User">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <association property="department" javaType="Department" column="department_id" select="getDepartmentById" />
</resultMap>

在这个例子中,User对象有一个Department类型的属性,该属性通过department_iddepartments表关联。当查询User对象时,如果设置了select属性,MyBatis会在需要时执行getDepartmentById查询来加载关联的Department对象。

<collection>

<collection>元素用于处理“一对多”的关系。它用于将多个结果行映射到一个集合或数组上。

属性说明

  • property:指定映射到哪个Java对象的属性(通常是一个集合或数组)。
  • ofType:指定集合或数组中元素的类型。
  • column:指定数据库中的哪一列用于作为外键。
  • foreignColumn:指定关联表中哪一列是外键。
  • select:指定一个用于加载关联对象的子查询ID(同样,在懒加载时有用)。
  • fetchType:可选,指定加载策略(默认为eager,即预加载;也可以设置为lazy,即懒加载)。

示例

<resultMap id="orderResultMap" type="Order">
    <id property="id" column="id" />
    <result property="orderDate" column="order_date" />
    <collection property="orderItems" ofType="OrderItem" column="id" foreignColumn="order_id" select="getOrderItemsByOrderId" />
</resultMap>

在这个例子中,Order对象有一个orderItems集合,它包含了与当前订单关联的多个OrderItem对象。当查询Order对象时,如果设置了select属性,MyBatis会在需要时执行getOrderItemsByOrderId查询来加载关联的OrderItem集合。

Springboot+mybatis详细代码实现

给出两个完整的示例:一个是使用<association>元素的一对一关系示例,另一个是使用<collection>元素的一对多关系示例。这两个示例都将基于Spring Boot + MyBatis框架。

示例环境准备

为了简化示例,我们假设已经搭建好了Spring Boot项目,并且已经配置好了MyBatis和数据库连接。

1. 实体类定义

首先定义几个简单的实体类:

  • User实体类
  • Department实体类
  • Order实体类
  • OrderItem实体类
// User.java
public class User {
    private Integer id;
    private String username;
    private Department department;

    // Getters and Setters
}

// Department.java
public class Department {
    private Integer id;
    private String name;

    // Getters and Setters
}

// Order.java
public class Order {
    private Integer id;
    private Date orderDate;
    private List<OrderItem> orderItems = new ArrayList<>();

    // Getters and Setters
}

// OrderItem.java
public class OrderItem {
    private Integer id;
    private Integer orderId;
    private String productName;
    private Integer quantity;

    // Getters and Setters
}
2. 映射接口定义

定义MyBatis的映射接口:

// UserMapper.java
@Mapper
public interface UserMapper {
    User getUserWithDepartment(Integer id);
}

// DepartmentMapper.java
@Mapper
public interface DepartmentMapper {
    Department getDepartmentById(Integer id);
}

// OrderMapper.java
@Mapper
public interface OrderMapper {
    Order getOrderWithOrderItems(Integer id);
}

// OrderItemMapper.java
@Mapper
public interface OrderItemMapper {
    List<OrderItem> getOrderItemsByOrderId(Integer orderId);
}
3. 映射文件定义

接下来定义对应的XML映射文件:

<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <resultMap id="userResultMap" type="com.example.entity.User">
        <id property="id" column="id" />
        <result property="username" column="username" />
        <association property="department" javaType="com.example.entity.Department"
                     column="department_id" select="com.example.mapper.DepartmentMapper.getDepartmentById" />
    </resultMap>
    <select id="getUserWithDepartment" resultMap="userResultMap">
        SELECT u.*, d.id AS department_id
        FROM users u
        LEFT JOIN departments d ON u.department_id = d.id
        WHERE u.id = #{id}
    </select>
</mapper>

<!-- DepartmentMapper.xml -->
<mapper namespace="com.example.mapper.DepartmentMapper">
    <resultMap id="departmentResultMap" type="com.example.entity.Department">
        <id property="id" column="id" />
        <result property="name" column="name" />
    </resultMap>
    <select id="getDepartmentById" resultMap="departmentResultMap">
        SELECT * FROM departments WHERE id = #{id}
    </select>
</mapper>

<!-- OrderMapper.xml -->
<mapper namespace="com.example.mapper.OrderMapper">
    <resultMap id="orderResultMap" type="com.example.entity.Order">
        <id property="id" column="id" />
        <result property="orderDate" column="order_date" />
        <collection property="orderItems" ofType="com.example.entity.OrderItem"
                    column="id" select="com.example.mapper.OrderItemMapper.getOrderItemsByOrderId" />
    </resultMap>
    <select id="getOrderWithOrderItems" resultMap="orderResultMap">
        SELECT o.*, oi.order_id
        FROM orders o
        LEFT JOIN order_items oi ON o.id = oi.order_id
        WHERE o.id = #{id}
    </select>
</mapper>

<!-- OrderItemMapper.xml -->
<mapper namespace="com.example.mapper.OrderItemMapper">
    <resultMap id="orderItemResultMap" type="com.example.entity.OrderItem">
        <id property="id" column="id" />
        <result property="orderId" column="order_id" />
        <result property="productName" column="product_name" />
        <result property="quantity" column="quantity" />
    </resultMap>
    <select id="getOrderItemsByOrderId" resultMap="orderItemResultMap">
        SELECT * FROM order_items WHERE order_id = #{id}
    </select>
</mapper>

示例代码

接下来,我们将使用Spring Boot Controller来演示如何使用上述定义的映射器。

4. 控制器定义

创建一个控制器来获取数据:

@RestController
@RequestMapping("/api")
public class DataController {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Integer id) {
        return userMapper.getUserWithDepartment(id);
    }

    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Integer id) {
        return orderMapper.getOrderWithOrderItems(id);
    }
}

这样我们就完成了两个示例的完整代码实现。用户可以通过/api/user/{id}/api/order/{id}来获取带有关联对象的数据。

请注意,这里的代码是简化的版本,实际项目中可能还需要考虑更多的细节,如异常处理、日志记录等。此外,数据库表结构也需要相应地定义好,以便映射关系能够正常工作。

注意点:

  1. 性能:懒加载可以减少初始查询的复杂性,但可能会增加后续访问关联对象时的数据库查询次数。预加载(默认行为)可以减少数据库查询次数,但可能会增加初始查询的复杂性和结果集的大小。
  2. 事务:懒加载可能导致跨多个事务边界的问题,特别是当在不同的会话或事务中访问关联对象时。预加载通常更适合在单个事务中处理所有数据。
  3. N+1查询问题:懒加载可能会导致N+1查询问题,即首先执行一个查询来获取N个主对象,然后对每个主对象执行一个额外的查询来获取其关联对象。这可以通过适当的查询优化或预加载来避免。
  4. 配置:确保正确配置MyBatis的懒加载和预加载策略,以避免不必要的性能问题或数据不一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值