MyBatis 提供了延迟加载(Lazy Loading)或称为按需加载的功能,允许你在真正需要数据时才去数据库查询。这通常是通过使用代理和拦截器来实现的。
在 MyBatis 中,延迟加载主要用于关联查询,特别是当关联的数据量很大,但你可能只需要其中一部分数据时。通过延迟加载,你可以避免不必要的数据库查询,从而提高性能。
以下是如何在 MyBatis 中实现延迟加载的步骤:
- 启用延迟加载:
在 MyBatis 的配置文件中(通常是 mybatis-config.xml
),你需要启用延迟加载。这可以通过设置 lazyLoadingEnabled
属性为 true
来实现。
xml
<settings> | |
<setting name="lazyLoadingEnabled" value="true"/> | |
<!-- 其他设置 --> | |
</settings> |
- 配置关联查询:
在你的映射文件(Mapper XML)中,你需要配置关联查询。例如,你可能有一个 User
实体,它有一个 Order
列表。你可以使用 <association>
或 <collection>
元素来配置这种关联。
为了支持延迟加载,你需要为这些关联配置 fetchType="lazy"
。但是,请注意,从 MyBatis 3.4.1 开始,fetchType
属性已被弃用,并使用 select
属性替代,以指定一个单独的查询来加载关联数据。
xml
<resultMap id="userResultMap" type="User"> | |
<id property="id" column="user_id"/> | |
<result property="username" column="user_name"/> | |
<collection property="orders" column="user_id" foreignColumn="user_id" | |
select="getOrdersByUserId" fetchType="lazy"/> | |
</resultMap> | |
<select id="getUserById" resultMap="userResultMap"> | |
SELECT * FROM users WHERE id = #{id} | |
</select> | |
<select id="getOrdersByUserId" resultType="Order"> | |
SELECT * FROM orders WHERE user_id = #{userId} | |
</select> |
但请注意,如上所述,从 MyBatis 3.4.1 开始,更推荐使用 select
属性而不是 fetchType
。
3. 使用关联数据:
当你从数据库获取一个 User
对象时,它的 orders
列表最初可能是一个代理对象。只有当你真正访问这个列表(例如,通过迭代它)时,MyBatis 才会执行 getOrdersByUserId
查询来加载数据。
4. 考虑性能:
虽然延迟加载可以提高性能,但它也可能导致 N+1 查询问题。例如,如果你有一个包含 100 个用户的列表,并且你迭代这个列表来访问每个用户的订单,那么你可能会有 101 个查询(一个用于获取用户列表,100 个用于获取每个用户的订单)。在这种情况下,你可能需要考虑使用 JOIN 查询或其他优化策略来减少数据库访问次数。
5. 其他注意事项:
- 如果你正在使用 MyBatis 与 Spring 集成,并且你遇到了与延迟加载相关的问题(例如,在事务外部访问代理对象时),你可能需要配置 OpenSessionInViewFilter 或 OpenSessionInViewInterceptor 来确保会话在请求期间保持打开状态。
- 在某些情况下,你可能需要显式地关闭延迟加载功能,以避免不必要的数据库访问。你可以通过设置
aggressiveLazyLoading
属性为false
来实现这一点。