使用Spring CrudRepository的Hibernate LazyInitializationException

我总是得到例外:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.knapp.vk.domain.Business.businessCategorySet, could not initialize proxy - no Session 

我不想把fetch设置为渴望。 什么是其他好的解决方案?

商业实体类:

 @Entity public class Business { @Id @GeneratedValue private int pk; @ManyToMany private Set businessCategorySet = new HashSet(); ... } 

BusinessRepository接口:

 import org.springframework.data.repository.CrudRepository; import org.springframework.transaction.annotation.Transactional; @Transactional public interface BusinessRepository extends CrudRepository { } 

配置:

 import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.hibernate4.HibernateExceptionTranslator; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableJpaRepositories(basePackages = "com.knapp.vk.repositorynew") @EnableTransactionManagement public class JPAConfiguration { @Bean public EntityManagerFactory entityManagerFactory() throws SQLException { return Persistence.createEntityManagerFactory("standardManager"); } @Bean public EntityManager entityManager(EntityManagerFactory entityManagerFactory) { return entityManagerFactory.createEntityManager(); } @Bean public PlatformTransactionManager transactionManager() throws SQLException { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory()); return txManager; } @Bean public HibernateExceptionTranslator hibernateExceptionTranslator() { return new HibernateExceptionTranslator(); } } 

所以你可以通过在Service中初始化businessCategoruSet来实现它,而不是在Repository中使用@Transactional而是在Service中使用它。 让我们在存储库中编写一些像id或业务列表获取业务的方法,并从服务中访问该方法。

 @Transactional public Class BusinessService{ @resource BusinessRepository businessRepository; public Business getBusiness(){ Business business = businessRepository.getBusiness(); //Here you should initialize BusinessCategorySet Object object = business.getBusinessCategoriesSet().size(); } } 

有关@Transactional更多详细信息, 请参阅此链接

您还可以在存储库中添加方法:

 @Transactional(readOnly = true) public List findAllEagerly() { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(Business.class); Root root = query.from(Business.class); root.fetch(Business_.businessCategorySet); return em.createQuery(query).getResultList(); } 

或者更容易在JpaRepository中使用@Query:

 @Query("SELECT b FROM Business b JOIN FETCH b.businessCategorySet") public List findAll(); 

我认为好的解决方案是使用@NamedEntityGraph

 @Entity @NamedEntityGraph(name = "Business.detail", attributeNodes = @NamedAttributeNode("businessCategorySet")) public class Business {...} 

并在存储库中

 public interface BusinessRepository extends CrudRepository { @EntityGraph(value = "Business.detail", type = EntityGraphType.LOAD) List findAll(); } 

也可以看看:

Spring Data存储库的自定义实现

配置Fetch-和LoadGraphs

Hibernate会话的范围在事务中。 因此,如果您在服务层开始交易,您的hibernate会话将可用到服务层。 如果你在另一个对象中调用任何对象,例如(business.getBusinessCategorySet())需要加载延迟,将导致抛出“org.hibernate.LazyInitializationException”。 要解决此问题,您有两个解决方案:1)在服务层2中加载所有相关对象。使用Open Session In View(OSIV)配置,它将使您的hibernate会话打开,直到查看图层。