![](/img/trans.png)
[英]Hibernate JPA, Spring MVC and 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.