Ich bin in der Mitte des Lernens Spring Data/Hibernate Zeug und konfrontiert mit bekannten Problem des lazy Loading in Hibernate. Ich habe versucht verschiedene Ansätze in Stackoverflow und anderen Ressourcen beschrieben, aber es sieht so aus, als ob sie nicht funktionieren. Ich verwende Hibernate im Coupé mit der Konfiguration der Federdatenanmerkung. Meine Ansätze waren:Federdaten Hibernate Lazy Loading
- Plain Laden von @OneToMany Abhängigkeit mit holen = FetchType.LAZY. Wie erwartet erhalte ich LazyInitializationException mit Nachricht über
nicht Proxy initialisieren konnte - keine Session
- Verwendung von Transaktions Repository. Gleiches Ergebnis wie für den ersten Punkt;
- Verwenden der Spring-Transaktionsvorlage. Gleiches Ergebnis;
- Verwenden von @NamedEntityGraph von JPA 2.1. Hier ist die Situation interessanter. Mein Test-Durchlauf, jedoch in SQL-Debugging kann ich sehen, dass Daten nicht lazy geladen werden, aber bei der ersten Abfrage des Repository. Eine andere Wörter-Kind-Tabelle ist zum ersten Mal mit der Eltern-Tabelle verbunden, wenn ich das Repository abfrage.
schob ich mein Testprojekt Github, so ist es möglich, es gibt https://github.com/megamaxskx/hibernate_lazy_fetch
AKTUALISIERT
Frühling Transaktion Template Ansatz zu überprüfen: Repository:
@Repository
public interface PlainParentRepository extends CrudRepository<PlainParent, Long> {
}
Konfiguration:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = REPOSITORY_LOCATION)
public class DBConfig {
public static final String REPOSITORY_LOCATION = "com.lazyloadingtest";
private static final String ENTITIES_LOCATION = "com.lazyloadingtest";
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.H2);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lemfb = new LocalContainerEntityManagerFactoryBean();
lemfb.setDataSource(dataSource());
lemfb.setJpaVendorAdapter(jpaVendorAdapter());
lemfb.setPackagesToScan(ENTITIES_LOCATION);
lemfb.setJpaProperties(hibernateProperties());
return lemfb;
}
protected Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.format_sql", true);
return properties;
}
}
Kinderklasse:
@Entity
public class EntityGraphChild implements Serializable {
public static long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private String name;
@ManyToOne
private PlainParent parent;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PlainParent getParent() {
return parent;
}
public void setParent(PlainParent parent) {
this.parent = parent;
}
}
Übergeordnete Klasse:
@Entity
public class PlainParent implements Serializable {
public static long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(targetEntity = PlainChild.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<PlainChild> children;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<PlainChild> getChildren() {
return children;
}
public void setChildren(Set<PlainChild> children) {
this.children = children;
}
}
Frühling Transaktionsvorlage Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
DBConfig.class,
})
public class SpringTransactionTemplateTest {
@Autowired
private PlainParentRepository repository;
@Autowired
private JpaTransactionManager transactionManager;
@Test
public void testRepository() {
PlainChild child1 = new PlainChild();
child1.setName("first child");
PlainChild child2 = new PlainChild();
child2.setName("second child");
PlainParent parent = new PlainParent();
parent.setId(1l);
HashSet<PlainChild> children = new HashSet<PlainChild>(Arrays.asList(child1, child2));
parent.setChildren(children);
repository.save(parent);
TransactionTemplate txTemplate = new TransactionTemplate();
txTemplate.setTransactionManager(transactionManager);
Set<PlainChild> fromDB = txTemplate.execute(new TransactionCallback<Set<PlainChild>>() {
public Set<PlainChild> doInTransaction(TransactionStatus transactionStatus) {
PlainParent fromDB = repository.findOne(1L);
return fromDB.getChildren();
}
});
assertEquals(2, fromDB.size());
}
}
NamedEntityGraph Ansatz:
Kind:
@Entity
public class EntityGraphChild implements Serializable {
public static long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private String name;
@ManyToOne
private EntityGraphParent parent;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public EntityGraphParent getParent() {
return parent;
}
public void setParent(EntityGraphParent parent) {
this.parent = parent;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EntityGraphChild child = (EntityGraphChild) o;
if (id != child.id) return false;
return name != null ? name.equals(child.name) : child.name == null;
}
}
Parent:
@Entity
@NamedEntityGraph(
name = "graph.Parent.children",
attributeNodes = @NamedAttributeNode(value = "children")
)
public class EntityGraphParent implements Serializable {
public static long serialVersionUID = 1L;
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(targetEntity = EntityGraphChild.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<EntityGraphChild> children;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<EntityGraphChild> getChildren() {
return children;
}
public void setChildren(Set<EntityGraphChild> children) {
this.children = children;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EntityGraphParent parent = (EntityGraphParent) o;
if (id != parent.id) return false;
if (name != null ? !name.equals(parent.name) : parent.name != null) return false;
return children != null ? children.equals(parent.children) : parent.children == null;
}
@Override
public int hashCode() {
int result = (int) (id^(id >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (children != null ? children.hashCode() : 0);
return result;
}
}
Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
DBConfig.class,
})
public class EntityGraphParentRepositoryTest {
@Autowired
private EntityGraphParentRepository repository;
@Test
public void testRepository() {
EntityGraphChild child1 = new EntityGraphChild();
child1.setName("first child");
EntityGraphChild child2 = new EntityGraphChild();
child2.setName("second child");
EntityGraphParent parent = new EntityGraphParent();
parent.setId(1l);
parent.setName("ParentGraph");
HashSet<EntityGraphChild> children = new HashSet<EntityGraphChild>(Arrays.asList(child1, child2));
parent.setChildren(children);
repository.save(parent);
System.out.println("--- Before querying repo");
EntityGraphParent fromDB = repository.findByName("ParentGraph");
System.out.println("--- After querying repo");
assertEquals(2, fromDB.getChildren().size());
System.out.println("--- Test finished");
}
}
Repository:
@Repository
public interface EntityGraphParentRepository extends CrudRepository<EntityGraphParent, Long> {
@EntityGraph(value = "graph.Parent.children", type = EntityGraph.EntityGraphType.LOAD)
public EntityGraphParent findByName(String name);
}
Beitrag der minimal einen entsprechenden Code hier, verknüpfe nicht nur –
sie das Beste, was Hibernate hat: sqlqueries –
Zum einen ist die vollständige Stack-Trace – LearningPhase