Java 如何使用JPA和Hibernate为关联的只读实体获取单个实例?

Java 如何使用JPA和Hibernate为关联的只读实体获取单个实例?,java,spring,hibernate,spring-boot,orm,Java,Spring,Hibernate,Spring Boot,Orm,我有两个实体: @Entity @Immutable @Cacheable @Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY) public class DoseFrequency{ ..... } @Entity public class PrescriptionDrug { ..... @ManyToOne(optional=false) @JoinCo

我有两个实体:

@Entity
@Immutable
@Cacheable
@Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
public class DoseFrequency{
   .....
} 

@Entity
public class PrescriptionDrug {

     .....
    @ManyToOne(optional=false)
    @JoinColumn(name="doseFrequency")   
    public DoseFrequency getDoseFrequency() {
        return doseFrequency;
     }

}
DoseFrequency是一个只读实体,PrescriptionDrug关联了一个DoseFrequency。我希望每次加载一个或多个处方药时,剂量顺序的实例不会重复

我知道DoseFrequency实例将缓存在hibernate的一级缓存中,但加载是在几个会话中完成的(这是一个web应用程序)。我使用了二级缓存,但该缓存不存储实例,只序列化实体

我使用Tuplizer在DoseFrequency中实现了这一行为,但我不知道是否有其他方法可以实现这一点

@Entity
@Immutable
@Cacheable
@Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
@Tuplizer(impl=DoseFrequencyTuplizer.class)
public class DoseFrequency {
   ....
}


public class DoseFrequencyTuplizer extends PojoEntityTuplizer {

    public DoseFrequencyTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
    }

    @Override
    protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) {
        return new DoseFrequencyInstantiator(DoseFrequency.class.getName(),entityMetamodel,persistentClass,null);
    }

    }


public class DoseFrequencyInstantiator implements Instantiator {

    private final Class targetClass;
    protected PojoEntityInstantiator pojoEntityInstantiator;

    public DoseFrequencyInstantiator(String targetClassName, EntityMetamodel entityMetamodel,
            PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) {
        try {
            this.targetClass = Class.forName(targetClassName);
        } catch (ClassNotFoundException e) {
            throw new HibernateException(e);
        }

        pojoEntityInstantiator = new PojoEntityInstantiator(entityMetamodel, persistentClass, optimizer);

    }

    @Override
    public Object instantiate(Serializable id) {
        DoseFrequency df = MedereEMRCache.instance.findDoseFrequencyByID(Long.valueOf(id.toString()));
        if (df == null) {
            return pojoEntityInstantiator.instantiate(id);
        }
        return df;
    }

    @Override
    public Object instantiate() {
        return instantiate(null);
    }

    @Override
    public boolean isInstance(Object object) {
        try {
            return targetClass.isInstance(object);
        } catch (Throwable t) {
            throw new HibernateException("could not get handle to entity as interface : " + t);
        }
    }

}
我知道这些实例将在应用程序的所有线程之间共享,但它们被视为只读,因此不应修改它们

这种方法正确吗


谢谢

您也可以使用
LoadEventListener
始终为同一实例提供服务。然而,由于实体是不可变的,因此不需要此功能,因此,即使您有它的多个副本,它仍然是不可变的

而且,即使您实现了一个单例模式,它也只会在每个JVM中执行,所以我不明白您为什么要实现这个请求


仅根据
EntityManager
将实体视为单例。

谢谢Vlad的回答。在VisualVM的采样器中,每次我加载inmutable对象时,它们的实例总是上升(当然GC会清理它们)。我希望避免像那些实体的单例一样实现。我将尝试LoadEventListener,再次感谢您