簡體   English   中英

使用Spring CrudRepository的Hibernate LazyInitializationException

[英]Hibernate LazyInitializationException using Spring CrudRepository

我總是得到例外:

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<BusinessCategory> businessCategorySet = new HashSet<BusinessCategory>();

...
}

BusinessRepository接口:

import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface BusinessRepository extends CrudRepository<Business, Integer>
{

}

配置:

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<Business> findAllEagerly() {
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Business> query = builder.createQuery(Business.class);
    Root<Business> 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<Business> findAll();

我認為好的解決方案是使用@NamedEntityGraph

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

並在存儲庫中

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

也可以看看:

Spring Data存儲庫的自定義實現

配置Fetch-和LoadGraphs

Hibernate會話的范圍在事務中。 因此,如果您在服務層開始交易,您的休眠會話將可用到服務層。 如果你在另一個對象中調用任何對象,例如(business.getBusinessCategorySet())需要加載延遲,將導致拋出“org.hibernate.LazyInitializationException”。 要解決此問題,您有兩個解決方案1)在服務層2中加載所有相關對象。使用Open Session In View(OSIV)配置,它將使您的休眠會話打開,直到查看圖層。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM