Hibernate懒/急加载示例

这篇文章将重点讨论为什么以及如何在应用程序中使用称为LAZYEAGER加载的概念,以及如何使用Spring的休眠模板以EAGER方式加载LAZY实体。

当然,正如标题本身所暗示的那样,我们将通过一个示例来说明这一点。 场景就是这样;

您是一个有很多玩具的孩子的父母。 但是当前的问题是,只要您打电话给他(我们假设您有一个男孩),他也会带着所有玩具来找您。 现在这是一个问题,因为您不希望他一直都随身携带玩具。

因此,作为理论上的父母,您会继续前进,并将孩子的玩具定义为LAZY。 现在,每当您打电话给他时,他都会不带玩具来到您身边。

但是您面临另一个问题。 当需要进行家庭旅行时,您希望他带上他的玩具,因为否则孩子会厌倦这次旅行。 但是,由于您对孩子的玩具严格执行LAZY,因此您无法要求他随身携带玩具。 这是EAGER提取起作用的地方。 首先让我们看看我们的领域类。

package com.fetchsample.example.domain;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * Holds information about the child
 * 
 * @author dinuka.arseculeratne
 * 
 */
@Entity
@Table(name = 'CHILD')
@NamedQuery(name = 'findChildByName', query = 'select DISTINCT(chd) from Child chd left join fetch chd.toyList where chd.childName=:chdName')
public class Child {

 public static interface Constants {
  public static final String FIND_CHILD_BY_NAME_QUERY = 'findChildByName';

  public static final String CHILD_NAME_PARAM = 'chdName';
 }

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 /**
  * The primary key of the CHILD table
  */
 private Long childId;

 @Column(name = 'CHILD_NAME')
 /**
  * The name of the child
  */
 private String childName;

 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 /**
  * The toys the child has. We do not want the child to have the same toy more than
  * once, so we have used a set here.
  */
 private Set<Toy> toyList = new HashSet<Toy>();

 public Long getChildId() {
  return childId;
 }

 public void setChildId(Long childId) {
  this.childId = childId;
 }

 public String getChildName() {
  return childName;
 }

 public void setChildName(String childName) {
  this.childName = childName;
 }

 public Set<Toy> getToyList() {
  return toyList;
 }

 public void addToy(Toy toy) {
  toyList.add(toy);
 }

}
package com.fetchsample.example.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Hols data related to the toys a child possess
 * 
 * @author dinuka.arseculeratne
 * 
 */
@Entity
@Table(name = 'TOYS')
public class Toy {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = 'TOY_ID')
 /**
  * The primary key of the TOYS table
  */
 private Long toyId;

 @Column(name = 'TOY_NAME')
 /**
  * The name of the toy
  */
 private String toyName;

 public Long getToyId() {
  return toyId;
 }

 public void setToyId(Long toyId) {
  this.toyId = toyId;
 }

 public String getToyName() {
  return toyName;
 }

 public void setToyName(String toyName) {
  this.toyName = toyName;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((toyName == null) ? 0 : toyName.hashCode());
  return result;
 }

 @Override
 /**
  * Overriden because within the child class we use a Set to
  * hold all unique toys
  */
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Toy other = (Toy) obj;
  if (toyName == null) {
   if (other.toyName != null)
    return false;
  } else if (!toyName.equals(other.toyName))
   return false;
  return true;
 }

 @Override
 public String toString() {
  return 'Toy [toyId=' + toyId + ', toyName=' + toyName + ']';
 }

}

如您所见,我们有两个简单的实体分别代表孩子和玩具。 这个孩子与这些玩具有一对多的关系,这意味着一个孩子可以拥有许多玩具(哦,我多么想念我的童年时代)。 之后,我们需要与数据进行交互,因此让我们继续定义DAO(数据访问对象)接口和实现。

package com.fetchsample.example.dao;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.fetchsample.example.domain.Child;

/**
 * The basic contract for dealing with the {@link Child} entity
 * 
 * @author dinuka.arseculeratne
 * 
 */
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public interface ChildDAO {

 /**
  * This method will create a new instance of a child in the child table
  * 
  * @param child
  *            the entity to be persisted
  */
 public void persistChild(Child child);

 /**
  * Retrieves a child without his/her toys
  * 
  * @param childId
  *            the primary key of the child table
  * @return the child with the ID passed in if found
  */
 public Child getChildByIdWithoutToys(Long childId);

 /**
  * Retrieves the child with his/her toys
  * 
  * @param childId
  *            the primary key of the child table
  * @return the child with the ID passed in if found
  */
 public Child getChildByIdWithToys(Long childId);

 /**
  * Retrieves the child by the name and with his/her toys
  * 
  * @param childName
  *            the name of the child
  * @return the child entity that matches the name passed in
  */
 public Child getChildByNameWithToys(String childName);

}
package com.fetchsample.example.dao.hibernate;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.fetchsample.example.dao.ChildDAO;
import com.fetchsample.example.domain.Child;

/**
 * The hibernate implementation of our {@link ChildDAO} interface
 * 
 * @author dinuka.arseculeratne
 * 
 */
public class ChildDAOHibernateImpl extends HibernateDaoSupport implements
  ChildDAO {

 /**
  * {@inheritDoc}
  */
 public void persistChild(Child child) {
  getHibernateTemplate().persist(child);
 }

 /**
  * {@inheritDoc}
  */
 public Child getChildByIdWithoutToys(Long childId) {
  return getHibernateTemplate().get(Child.class, childId);
 }

 /**
  * {@inheritDoc}
  */
 public Child getChildByIdWithToys(Long childId) {
  Child child = getChildByIdWithoutToys(childId);
  /**
   * Since by default the toys are not loaded, we call the hibernate
   * template's initialize method to populate the toys list of that
   * respective child.
   */
  getHibernateTemplate().initialize(child.getToyList());
  return child;
 }

 /**
  * {@inheritDoc}
  */
 public Child getChildByNameWithToys(String childName) {
  return (Child) getHibernateTemplate().findByNamedQueryAndNamedParam(
    Child.Constants.FIND_CHILD_BY_NAME_QUERY,
    Child.Constants.CHILD_NAME_PARAM, childName).get(0);

 }

}

一个简单的合同。 我有四种主要方法。 当然,第一个只是将子实体持久化到数据库中。

第二种方法通过传入的主键来检索Child,但不提取玩具。

第三种方法首先获取Child,然后使用Hibernate模板的initialize()方法检索Child的玩具。 请注意,当您调用initialize()方法时,hibernate将把您LAZY定义的集合获取到您检索的Child代理中。

最终方法还可以检索“儿童”的玩具,但这一次使用命名查询。 如果返回到Child实体的Named查询,则可以看到我们使用了“ left join fetch ”。 当返回有资格的Child实体时,实际上是关键字fetch也会初始化玩具集合。 最后,我有我的主班来测试我们的功能;

package com.fetchsample.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.fetchsample.example.dao.ChildDAO;
import com.fetchsample.example.domain.Child;
import com.fetchsample.example.domain.Toy;

/**
 * A test class
 * 
 * @author dinuka.arseculeratne
 * 
 */
public class ChildTest {

 public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext(
    'com/fetchsample/example/spring-context.xml');

  /**
   * First we initialize a child
   */
  Child child = new Child();

  /**
   * A cool ben 10 action figure
   */
  Toy ben10 = new Toy();
  ben10.setToyName('Ben 10 figure');

  /**
   * A even more cooler spider man action figure
   */
  Toy spiderMan = new Toy();
  spiderMan.setToyName('Spider man figure');

  child.setChildName('John');
  /**
   * Add the toys to the collection
   */
  child.addToy(ben10);
  child.addToy(spiderMan);

  ChildDAO childDAO = (ChildDAO) context.getBean('childDAO');

  childDAO.persistChild(child);

  Child childWithoutToys = childDAO.getChildByIdWithoutToys(1L);
  // The following line will throw a lazy initialization error since we have
  // defined fetch type as LAZY in the Child domain class.
  // System.out.println(childWithToys.getToyList().size());

  Child childWithToys = childDAO.getChildByIdWithToys(1L);
  System.out.println(childWithToys.getToyList().size());

  Child childByNameWithToys = childDAO.getChildByNameWithToys('John');

  System.out.println(childByNameWithToys.getToyList().size());

 }
}

将基础实体定义为LAZY是一种好习惯,因为在很多情况下,您可能不希望实体内的集合,而只想与基础实体中的数据进行交互。 但是,如果需要集合的数据,则可以使用前面提到的任何一种方法。

今天就是这样。 对于任何想尝试该示例的人,我都在这里上传了该示例。

参考:我的旅程” IT博客中的JCG合作伙伴 Dinuka Arseculeratne 举例说明使用休眠模式进行延迟/延迟加载


翻译自: https://www.javacodegeeks.com/2012/08/hibernate-lazyeager-loading-example.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值