繁体   English   中英

Spring MVC的Hibernate LazyInitializationException

[英]Hibernate LazyInitializationException with Spring MVC

问题

使用Kolorbot的Spring MVC 4快速入门原型,我创建了一个实体,一个存储库和一个服务类,可通过控制器方法访问该类。 在我的实体中,我通过延迟获取与另一个实体建立了ManyToOne关系。

在我的控制器方法中,我调用服务的方法,该方法本身又在存储库中调用一个方法,该方法最终获取所需的数据并将其传递到各个层。

访问控制器方法中指向相关实体的实体属性时,我收到“ LazyInitializationException”。

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

研究并尝试解决问题

在阅读问题时,我偶然发现了解决方案,这些解决方案描述了@Transactional批注的用法,该方法无济于事,或者包含OpenEntityManagerInViewFilter,后者应强制会话保持打开状态,直到处理控制器的方法为止。

包含OpenEntityManagerInViewFilter:

@Override
protected Filter[] getServletFilters() {
    OpenEntityManagerInViewFilter openEntityManagerInViewFilter = new OpenEntityManagerInViewFilter();
    openEntityManagerInViewFilter.setBeanName("openEntityManagerInViewFilter");

    ...

    return new Filter[] {openEntityManagerInViewFilter, characterEncodingFilter, securityFilterChain};
}

使用过滤器会导致以下异常:

org.hibernate.HibernateException: Javassist Enhancement failed: com.example.package.RelatedEntity
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxy(JavassistLazyInitializer.java:143)
at org.hibernate.proxy.pojo.javassist.JavassistProxyFactory.getProxy(JavassistProxyFactory.java:73)

RelatedEntity是我尝试通过我感兴趣的原始实体访问的对象。

通过将延迟获取机制设置为false,我收到以下异常(在控制器的方法中引发):

 
 
 
 
  
  
  Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly] with root cause javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:72)
 
 
  

通过删除存储库的findEntityById()方法中的try / catch块(请参见下文)并添加注释@Transactional(noRollbackFor = PersistenceException.class)我能够启用急切加载。 但这只是一个临时解决方案。 尽管如此,我还是想使用延迟获取。


源代码部分

服务方法返回的实体类:

@Entity
@Table(name = "Entity")
@NamedQuery(
        name = Entity.FIND_BY_ID,
        query = "select e from Entity e where e.id = :id"
)
public class Entity {

    public static final String FIND_BY_ID = "Entity.findById";

    @Id
    @Column(name = ID)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Getter
    private Long id;

    ...

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name=RelatedEntity.ID)
    @Getter
    private RelatedEntity relatedEntity;

    ...

    protected Entity() {}

    public Entity(String param1) {
        ...
    }
}

以及我尝试通过Entity实例访问的RelatedEntity:

@Entity
@Table(name = "RELATED_ENTITY")
@NamedQuery(name = RelatedEntity.FIND_BY_ID, query = "select re from RelatedEntity re where re.id = :id")
public class RelatedEntity {

    public static final String FIND_BY_ID = "RelatedEntity.findById";
    public static final String ID = "RE_ID";

    @Id
    @Column(name=ID)
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    ...

    @OneToMany(mappedBy="relatedEntity")
    private List<Entity> entities;

    ...

    protected RelatedEntity() {}

    public RelatedEntity(String param1) {
        ...
    }

}

最后,存储库和服务类:

@Repository
public class EntityRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional(noRollbackFor = PersistenceException.class)
    public List<Entity> findEntityById(Long id) {
        return entityManager.createNamedQuery(Entity.FIND_BY_ID, Entity.class)
                .setParameter("id", id)
                .getResultList();
    }

}

@Service
public class DefaultEntityService implements EntityService {

    @Autowired
    EntityRepository entityRepository;

    ...

    @Override
    public List<Entity> findEntitiesById(Long id) {
        return entityRepository.findAgreementById(id);
    }

    ...
}

我不确定发生了什么,但突然在访问控制器和视图中的实体属性时,OpenEntityManagerInViewFilter似乎可以正常工作,并且会话仍处于打开状态。 Hibernate社区文档中详细记录了对延迟获取机制和避免LazyInitializationException的可能解决方案的进一步了解。

通过服务层中的Hibernate.initialize()初始化延迟获取的对象是一种有效的替代方法,但会产生过多的不必要开销。

为了确保您的延迟加载请求已绑定到会话,应在服务层中将其初始化:

@Override
public List<Entity> findEntitiesById(Long id) {
    List<Entity> entityList = entityRepository.findAgreementById(id);
    for (Entity e: entityList){
        Hibernate.initialize(e.getRelatedEntity());
    }
    return entityList; 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM