Java延迟加载建议

本文介绍了在Java中实现懒加载的多种方法,包括正常的初始化、双重检查模式、静态内部类懒汉模式以及单重检查模式等,并提供了具体示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.xqh.test;

/**
 * 大多数的域应该正常地进行初始化,而不是延迟初始化。如果为了达到性能目的,或者为了破坏有害的初始化循环
 * 而必须延迟初始化一个域,就可以使用相应的延迟初始化方法。
 * 对于实例域,就使用双重检查模式;
 * 对于静态域,则使用lazy initialization holder class idiom;
 * 对于可以接受重复初始化的实例域,也可以考虑使用单重检查模式
 * @author Snway
 *
 */
public class LazyInit {
	private final String field_0 = getFieldValue(); // 正常初始化
	
	// 延迟加载 方法1
	private String field_3;
	
	synchronized String getStr1() {
		if (field_3 == null) 
			field_3 = getFieldValue();
		return field_3;
	}
	
	// 延迟加载 方法2 出于性能考虑而需要对静态域使用初始化,就使用lazy initialization holder class 模式
	private static class FieldHolder {
		static final String field = getFieldValue();
	}
	
	static String getField() {
		return FieldHolder.field;
	}
	
	//延迟加载 方法3 如果出于性能考虑而需要对实例域使用延迟初始化,就使用双重检查模式
	//第一次检查时没有锁定,看看该域是否被初始化了;第二次检查时锁定
	private volatile String field_1;
	
	String getField_1() {
		String result = field_1;
		if (result == null) { // 第一次检查
			synchronized(this) { // 第二次检查,要是没有被初始化才进行初始化。
				result = field_1;
				if (result == null)
					field_1 = result = getFieldValue();
			}
		}
		return result;
	}
	
	// 延迟加载 方法4 如果可能需要延迟初始化一个可以接受重复初始化的实例域——单重检查模式
	
	private volatile String field_2;
	
	String getField_2() {
		String result = field_2;
		if (result == null)
			field_2 = result = getFieldValue();
		return result;
	}
	
	public static String getFieldValue() {
		return "xqh";
	}
}


### Java MyBatis 延迟加载的实现与用法 #### 配置延迟加载 MyBatis 提供了全局配置选项来启用或禁用延迟加载。通过在 `Configuration` 类中设置 `lazyLoadingEnabled` 属性为 `true`,可以开启全局的延迟加载功能[^4]。此外,还可以通过设置 `aggressiveLazyLoading` 属性来控制是否在方法调用时加载所有属性,或者仅按需加载特定属性。 ```xml <settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings> ``` 上述配置启用了延迟加载,并且设置了非激进模式,即每个属性将按需加载而不是一次性加载所有关联数据[^4]。 #### 实现机制 MyBatis 的延迟加载是基于动态代理和反射机制实现的。当一个对象被标记为延迟加载时,MyBatis 会创建一个代理对象。这个代理对象会在实际访问关联属性时触发 SQL 查询以加载数据[^3]。具体来说,当用户尝试访问某个延迟加载的属性时,代理对象会拦截该访问并执行相应的查询操作。 #### 使用方法 在使用 MyBatis 的延迟加载时,可以通过 XML 映射文件或注解的方式来定义关联关系。以下是一个基于 XML 的示例: ```xml <resultMap id="userResultMap" type="User"> <id property="id" column="user_id"/> <result property="name" column="user_name"/> <association property="profile" javaType="Profile" select="selectProfile" column="user_id" fetchType="LAZY"/> </resultMap> <select id="selectUser" resultMap="userResultMap"> SELECT * FROM users WHERE id = #{id} </select> <select id="selectProfile" resultType="Profile"> SELECT * FROM profiles WHERE user_id = #{userId} </select> ``` 在这个例子中,`profile` 属性被配置为延迟加载。只有当代码显式访问 `user.getProfile()` 时,才会触发对 `selectProfile` 查询的调用[^2]。 如果使用注解方式,则可以通过 `@One` 或 `@Many` 注解来定义延迟加载的关联关系: ```java public class User { private Integer id; private String name; @One(select = "com.example.mapper.ProfileMapper.selectProfile", fetchType = FetchType.LAZY) private Profile profile; // getters and setters } ``` 上述代码片段展示了如何通过注解的方式定义一个延迟加载的一对一关系[^5]。 #### 注意事项 - 延迟加载可能会导致 N+1 查询问题。因此,在设计查询时需要权衡是否使用延迟加载。 - 确保数据库连接在延迟加载发生时仍然可用,否则可能会引发异常。 - 如果某些属性总是需要一起加载,考虑使用预加载(eager loading)以避免多次查询带来的性能开销。 #### 示例代码 以下是一个完整的示例,展示了如何在 MyBatis 中配置和使用延迟加载: ```java @Mapper public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") @Results({ @Result(id = true, property = "id", column = "user_id"), @Result(property = "name", column = "user_name"), @Result(property = "profile", column = "user_id", one = @One(select = "selectProfile", fetchType = FetchType.LAZY)) }) User selectUserById(int id); @Select("SELECT * FROM profiles WHERE user_id = #{userId}") Profile selectProfile(int userId); } ``` ```java public class UserService { @Autowired private UserMapper userMapper; public void getUserWithProfile(int id) { User user = userMapper.selectUserById(id); System.out.println(user.getName()); // 不会触发 profile 加载 System.out.println(user.getProfile().getDetail()); // 触发 profile 加载 } } ``` ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值