gpt4 book ai didi

java - spring data hibernate 延迟加载

转载 作者:行者123 更新时间:2023-11-29 04:47:21 26 4
gpt4 key购买 nike

我正在学习 Spring Data/Hibernate 的东西,并且面临着 Hibernate 中延迟加载的已知问题。我尝试了 stackoverflow 和其他资源中描述的不同方法,但看起来它们不起作用。我在 coupe 中使用 hibernate 和 spring 数据注释配置。我的方法是:

  1. 使用fetch = FetchType.LAZY 简单加载@OneToMany 依赖项。正如预期的那样,我收到了关于
  2. 的消息的 LazyInitializationException

could not initialize proxy - no Session

  1. 使用事务存储库。与第一点相同的结果;
  2. 使用 Spring 事务模板。相同的结果;
  3. 使用 JPA 2.1 的@NamedEntityGraph。这里的情况更有趣。我的测试通过了,但是在 SQL 调试中我可以看到数据没有延迟加载,但是在我第一次查询存储库时。换句话说,子表在我第一次查询存储库时连接到父表。

我把我的测试项目推送到了github,所以可以在那里查看 https://github.com/megamaxskx/hibernate_lazy_fetch

已更新

Spring 事务模板方法:存储库:

@Repository
public interface PlainParentRepository extends CrudRepository<PlainParent, Long> {

}

配置:

@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;
}

}

子类:

@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;
}
}

父类:

@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;
}
}

Spring事务模板测试:

@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 方法:

child :

@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;

}
}

家长:

@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;
}
}

测试:

@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
public interface EntityGraphParentRepository extends CrudRepository<EntityGraphParent, Long> {

@EntityGraph(value = "graph.Parent.children", type = EntityGraph.EntityGraphType.LOAD)
public EntityGraphParent findByName(String name);
}

最佳答案

您误解了 JPA 中的关系惰性。当您将 OneToMany 关系标记为惰性关系时,实际上变为惰性的是您的 Set 而不是 getChildren。换句话说,你需要访问 Set 的内容来触发惰性关系被获取,为此你需要一个事务。按照您的问题:

  1. 由于您的外部代码不是事务性的,因此事务本身会在存储库方法调用结束时提交。 Session 对象不再可访问,因为它已绑定(bind)到事务,您会收到错误消息。
  2. 在您的事务模板中,您访问的是 getChildren,而不是子集的内容。这就是我在简短部分所说的内容。
  3. EntityGraphs 旨在覆盖映射中定义的关系获取策略。由于您已将 Parent.children 字段标记为要在图表中获取,因此现在需要在应用该图表的每个数据库交互时立即获取该字段。

关于java - spring data hibernate 延迟加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36655341/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com