當然,正如標題本身所暗示的那樣,我們將通過一個示例來說明這一點。 場景就是這樣;
您是一個有很多玩具的孩子的父母。 但是當前的問題是,只要您打電話給他(我們假設您有一個男孩),他也會帶著所有玩具來找您。 現在這是一個問題,因為您不希望他一直都隨身攜帶玩具。
因此,作為理論上的父母,您會繼續前進,并將孩子的玩具定義為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;}@Overridepublic 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;}@Overridepublic 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 implementsChildDAO {/*** {@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