spring数据hibernate延迟加载

时间:2016-04-15 19:24:36

标签: java spring hibernate jpa spring-data

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

  1. 使用 fetch = FetchType.LAZY 正常加载@OneToMany依赖项。正如预期的那样,我收到 LazyInitializationException ,其中包含有关
  2. 的消息
      

    无法初始化代理 - 没有会话

    1. 使用事务存储库。与第一点相同的结果;
    2. 使用Spring事务模板。相同的结果;
    3. 使用JPA 2.1的@NamedEntityGraph。这里的情况更有趣。我的测试通过,但是在SQL调试中我可以看到数据没有加载延迟,但是我第一次查询存储库。另一个单词子表第一次加入父表时我正在查询存储库。
    4. 我将我的测试项目推送到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方法:

      子:

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

1 个答案:

答案 0 :(得分:2)

你误解了JPA中的关系懒惰。当你将OneToMany关系标记为懒惰关系时,它实际上变得懒惰而不是getChildren。换句话说,您需要访问Set的内容以触发要获取的延迟关系,并且您需要一个事务。关注您的问题:

  1. 由于您的外部代码不是事务性的,因此事务本身会在存储库方法调用结束时提交。 Session对象不再可访问,因为它绑定到事务并且您收到错误。
  2. 在您的交易模板中,您可以访问getChildren,而不是儿童套装的内容。这就是我在简短部分所谈论的内容。
  3. EntityGraphs旨在覆盖映射中定义的关系提取策略。由于您已在图表中标记了Parent.children字段,因此现在需要在应用此图表的每个数据库交互时急切地获取此字段。