使用Kolorbot' s Spring MVC 4 Quickstart archetype我创建了一个实体,一个存储库和一个服务类,可以通过控制器方法访问。在我的实体中,我通过懒惰的方式获取与另一个实体的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) {
...
}
}
我尝试通过实体实例访问的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似乎工作,并且在我的控制器和视图中访问实体的属性时会话仍然打开。进一步深入了解延迟提取机制以及避免LazyInitializationException的可能解决方案已在Hibernate Community Documentation中详细记录。
在服务层中通过Hibernate.initialize()
初始化延迟取出的对象是一种有效的替代方法,但会产生太多不必要的开销。
答案 0 :(得分:1)
为了确保您的延迟加载请求绑定到会话,您应该在服务层初始化它:
@Override
public List<Entity> findEntitiesById(Long id) {
List<Entity> entityList = entityRepository.findAgreementById(id);
for (Entity e: entityList){
Hibernate.initialize(e.getRelatedEntity());
}
return entityList;
}