在开发博客项目的时候实体类之间有一对多和多对一的关系,看了一下API文档和网上的分享,谈一下一对多关系中,set集合的lazy属性和fetch属性不同搭配的理解。
不同配置的结果如下:
下面用测试说明具体情况。
User和category是一对多关系,实体类代码如下。
public class User {
private Long user_id;
private String username;
private String password;
private String status;//状态
private String details;//备注
private Set<Category> categories = new HashSet<Category>();
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
}
public class Category {
private Long cate_id;
private String title;
private User user;
public Long getCate_id() {
return cate_id;
}
public void setCate_id(Long cate_id) {
this.cate_id = cate_id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
对应的映射文件配置,下面测试仅改变User类的映射文件中Set标签的lazy和fetch属性:
<hibernate-mapping package="com.dengtuzi.domain">
<class name="User" table="dtb_user" >
<id name="user_id" >
<generator class="native"></generator>
</id>
<property name="username"></property>
<property name="password"></property>
<property name="status"></property>
<property name="details"></property>
<set name="categories" lazy="true" fetch="select">
<key column="cate_user_id"></key>
<one-to-many class="Category" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping package="com.dengtuzi.domain">
<!-- -->
<class name="Category" table="dtb_category">
<id name="cate_id">
<generator class="native"></generator>
</id>
<property name="title" ></property>
<many-to-one name="user" column="cate_user_id" class="User"></many-to-one>
</class>
</hibernate-mapping>
1. lazy="true" fetch="select"
测试代码:
@Test
public void fun1(){
//加载配置
Configuration config = new Configuration().configure();
//获得factory
SessionFactory factory = config.buildSessionFactory();
//获得session
Session session = factory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 14l);//断点位置
//查询用户关联的set集合
Set<Category> categories = user.getCategories();
//使用数据
System.out.println(categories);
//提交事务,关闭session
transaction.commit();
session.close();
下断点,开始调试。
往下走一步,执行完user查询,控制台输出的sql语句:
再往下走一步,执行该用户关联的categories的查询,控制没有输出。
继续往下走,执行打印categories代码,此时控制台输出结果:
从测试的结果可以看到,查询user时并没有进行关联集合的查询,获取categories的值也没有进行查询,使用categories数据时才进行查询操作,即开启了延迟加载,并且user和categories的查询都用的是单表查询语句。
2.lazy="false" fetch="select"
在User的映射文件更改Set集合属性配置,使用同样的测试代码。
执行user的查询语句后,控制台信息:
对user查询的同时,立即对关联的categories集合也进行了查询,也就是
关闭了关联集合的延迟加载,而且user和categories的查询都使用了
单表查询语句。
3.lazy="extra" fetch="select"
测试结果和情况1相同,看不出区别,需要修改测试代码。看了官方API文档,里面描述是
使用"extra",此时大多数操作不会初始化集合类(适用于非常大的集合)
修改测试代码在打印categories前加入一条打印语句:
@Test
public void fun1(){
//加载配置
Configuration config = new Configuration().configure();
//获得factory
SessionFactory factory = config.buildSessionFactory();
//获得session
Session session = factory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 14l);
//查询用户关联的set集合
Set<Category> categories = user.getCategories();
//使用数据
System.out.println(categories.isEmpty());
System.out.println(categories);
//提交事务,关闭session
transaction.commit();
session.close();
}
执行user查询后控制台打印的结果:
继续往下执行,执行categories查询时没有加载数据,控制台没有打印信息。
执行打印categories集合是否为空的语句,控制台打印信息:
、继续往下执行,打印categories,此时控制台输出信息:
从测试结果可以看到,效果和lazy=“true”效果差不多,查询时并不加载数据,使用时才查询加载。唯一区别是,lazy="extra"时,如果使用集合时,如果不涉及集合内容(判断是否空集,查询集合size),也是不会加载集合数据。
4.lazy="true" fetch="join"
调试结果:
查询user的时候使用
多表查询语句,同时把关联的categories集合也进行了查询,也就是
关闭了延迟加载,lazy属性被无效化了。
5.lazy="false" fetch="join"
测试结果同情况4一致,使用多表查询,关闭延迟加载。
6.lazy="extra" fetch="join"
测试结果同情况4一致,使用多表查询,关闭延迟加载。
7.lazy="true" fetch="subselect"
测试代码:
@Test
public void fun2(){
//加载配置
Configuration config = new Configuration().configure();
//获得factory
SessionFactory factory = config.buildSessionFactory();
//获得session
Session session = factory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//查询所有用户
String hql = "FROM User";
Query query = session.createQuery(hql);//断点位置
List<User> users = (List<User>)query.list();
System.out.println(users.get(0).getCategories().size());
System.out.println(users.get(0).getCategories());
//提交事务,关闭session
transaction.commit();
session.close();
}
查询所有user时,控制台信息:
打印categories集合size时候控制台信息:
继续执行,打印categories集合:
从测试结果来看,查询user时并不查询关联的categories集合,而是在使用categories时通过
子查询语句查询,即
开启了延迟加载。
8.lazy="false" select="subselect"
查询所有user时,控制台信息:
查询user时就立即
使用子查询语句查询关联的categories集合,即
关闭了延迟加载。
9.lazy="extra" select="subselect"
查询所有user时控制台信息:
打印categories集合size:
打印categories集合:
查询所有user的时候不查询关联的categories集合,不使用集合内数据时(判断是否为空,查询集合size)也不查询,只有使用到集合内元素数据时才
使用子查询语句进行查询,即
开启延迟加载。
10.结论
在不影响代码功能的多数情况下,效率最好的lazy="true",fetch="select",而这也是Hibernate默认配置。