我知道有很多“无法初始化代理-没有会话”的问题,但是我没有找到解决问题的答案。
问题是,当我委托fetchLazy
方法时,它会引发上述异常。这是我的服务类的简化版本:
服务
public abstract class Service<S extends Service<S,E>, E extends Entity> {
@PersistenceContext private EntityManager entityManager;
// person = personService.fetchLazy(person, Person::getCompany); OK
public E fetchLazy(E entity, Function<E,?> proxyMapper) {
E attachedEntity = entityManager.find(entity.getClass(), entity.getId());
Object proxy = proxyMapper.apply(attachedEntity);
if (!Hibernate.isInitialized(proxy)) { Hibernate.initialize(proxy); }
return attachedEntity;
}
// person = personService.fetch(person).lazy(Person::getCompany); EXCEPTION
public FetchBuilder fetch(E entity) { return new FetchBuilder((S) this, entity); }
public class FetchBuilder {
private final S service; private final E entity;
LazyFetchBuilder(E e, S s) { this.entity = e; this.service = s; }
public E lazy(E entity, Function<E,?> proxyMapper) {
return service.fetchLazy(entity, proxyMapper); // DELEGATE
}
}
}
PersonService
@Stateless
public class PersonService extends Service<PersonService,Person> { ... }
PersonBean
@Named @ViewScoped
public class PersonBean implements Serializable {
@EJB private PersonService personService;
@PostConstruct public void init() {
person = personService.getById(id);
person = personService.fetchLazy(person, Person::getCompany); // OK
person = personService.fetch(person).lazy(Person::getCompany); // EXCEPTION
}
}
答案 0 :(得分:1)
我将假定此服务是Java EE或Spring事务服务。声明式事务是基于代理的。当您使用依赖项注入获取服务的实例并调用事务方法时,实际上您会调用包装服务的事务代理的方法:
client ----------> transactional proxy -----------> service
- start the transaction
- call the service
- commit
-return the value returned by the service
致电fetchLazy()
时,一切正常:
致电fetch()
时,会发生以下情况
由于您从不使用实体管理器,因此该交易实际上无用。
现在,当您在返回的构建器上调用fetch()
时会发生什么?它在FetchBuilder的fetchLazy
实例变量上调用service
。 service
是实际服务实例的实例,而不是包装服务实例的代理的实例,因为您是用this
从服务实例本身对其进行初始化的。因此,您将绕过代理,因此这些交易就不会将对find()
的调用和公司的初始化包装起来。