И, конечно, как следует из названия, мы покажем это на примере. Сценарий как таковой;
Вы родитель, у которого есть ребенок с большим количеством игрушек. Но текущая проблема в том, что когда бы ты ни позвонил ему (мы предполагаем, что у тебя есть мальчик), он приходит к тебе со всеми своими игрушками. Теперь это проблема, так как вы не хотите, чтобы он все время носил свои игрушки.
Таким образом, будучи обоснованным родителем, вы идете вперед и определяете игрушки ребенка как ленивые. Теперь, когда вы звоните ему, он приходит к вам без игрушек.
Но вы столкнулись с другой проблемой. Когда придет время для семейной поездки, вы хотите, чтобы он взял с собой свои игрушки, потому что в противном случае ребенку будет скучно. Но так как вы строго обязали ЛЕНЗИ к игрушке ребенка, вы не можете попросить его взять с собой игрушки. Это где выборка EAGER вступает в игру. Давайте сначала посмотрим на наши доменные классы.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
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); }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
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 (объекта доступа к данным).
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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);} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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); }} |
Простой контракт. У меня есть четыре основных метода. Первый, конечно, просто сохраняет дочернюю сущность в базе данных.
Второй метод извлекает дочерний элемент по переданному первичному ключу, но не выбирает игрушки.
Третий метод сначала извлекает ребенка, а затем извлекает игрушки ребенка, используя метод initialize () шаблона Hibernate. Обратите внимание, что когда вы вызываете метод initialize (), hibernate извлекает вашу коллекцию, определенную LAZY, в дочерний прокси, который вы получили.
Последний метод также извлекает игрушки ребенка, но на этот раз с использованием именованного запроса. Если мы вернемся к Именованному запросу объекта Child, вы увидите, что мы использовали « выборку из левого соединения». Это выборка ключевых слов, которая фактически инициализирует коллекцию игрушек также при возврате объекта Child, который соответствует требованиям. Наконец у меня есть основной класс для тестирования нашей функциональности;
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
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 является хорошей практикой, поскольку во многих случаях вы можете не захотеть коллекций внутри сущности, а просто взаимодействовать с данными в вашей базовой сущности. Но в случае, если вам нужны данные ваших коллекций, вы можете использовать любой из методов, упомянутых ранее.
Это об этом на сегодня. Для тех, кто хочет опробовать пример, я загрузил его здесь .
Ссылка: Ленивая / Стремительная загрузка с использованием режима гибернации на примере нашего партнера JCG Динуки Арурилератне в блоге My Journey Through IT .