我在优化Hibernate查询以免执行联接或辅助选择时遇到了麻烦。
执行Hibernate查询(条件或hql)时,例如:
return getSession().createQuery(("from GiftCard as card where card.recipientNotificationRequested=1").list();
…,而where子句检查不需要与其他表进行任何联接的属性…,但是Hibernate仍与其他表进行完全联接(或辅助选择,具体取决于我如何设置fetchMode)。
有问题的对象(GiftCard)有几个ManyToOne关联,在这种情况下(但不一定是所有情况),我希望它们被延迟加载。我想要一个解决方案,可以控制执行查询时延迟加载的内容。
以下是GiftCard实体的外观:
@Entity @Table(name = "giftCards") public class GiftCard implements Serializable { private static final long serialVersionUID = 1L; private String id_; private User buyer_; private boolean isRecipientNotificationRequested_; @Id public String getId() { return this.id_; } public void setId(String id) { this.id_ = id; } @ManyToOne @JoinColumn(name = "buyerUserId") @NotFound(action = NotFoundAction.IGNORE) public User getBuyer() { return this.buyer_; } public void setBuyer(User buyer) { this.buyer_ = buyer; } @Column(name="isRecipientNotificationRequested", nullable=false, columnDefinition="tinyint") public boolean isRecipientNotificationRequested() { return this.isRecipientNotificationRequested_; } public void setRecipientNotificationRequested(boolean isRecipientNotificationRequested) { this.isRecipientNotificationRequested_ = isRecipientNotificationRequested; } }
如前所述
我想要一个 可以控制 执行查询时 延迟加载的内容 的解决方案
如果您有这样的映射
@Entity public class GiftCard implements Serializable { private User buyer; @ManyToOne @JoinColumn(name="buyerUserId") public User getBuyer() { return this.buyer; } }
默认情况下,任何 ToOne关系(例如@OneToOne和@ManyToOne)都是FetchType.EAGER,这意味着将始终对其进行提取。但是,这可能不是您想要的。当 我可以控制延迟加载的内容时, 您所说的 内容 可以翻译为“ 获取策略”* 。Action Book中的POJO支持这种模式(Notice方法签名)
public class GiftCardRepositoryImpl implements GiftCardRepository { public List<GiftCard> findGiftCardWithBuyer() { return sessionFactory.getCurrentSession().createQuery("from GiftCard c inner join fetch c.buyer where c.recipientNotificationRequested = 1").list(); } }
因此,根据您的用例,您可以创建自己的 find … With … And … 方法。它会照顾 您想要的东西
但这有一个问题:它不支持通用方法签名。对于每个@Entity存储库,您必须定义自定义 find … With … And 方法。因此,我向您展示了如何定义通用存储库
public interface Repository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> { void add(INSTANCE_CLASS instance); void remove(PRIMARY_KEY_CLASS id); void update(PRIMARY_KEY_CLASS id, UPDATABLE_INSTANCE_CLASS updatableInstance); INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id); INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id, FetchingStrategy fetchingStrategy); List<INSTANCE_CLASS> findAll(); List<INSTANCE_CLASS> findAll(FetchingStrategy fetchingStrategy); List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize); List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize, FetchingStrategy fetchingStrategy); List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria); List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria, FetchingStrategy fetchingStrategy); List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria); List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria, FetchingStrategy fetchingStrategy); }
但是, 有时 ,您不希望通用存储库接口定义所有方法。解决方案:创建一个AbstractRepository类,它将实现一个虚拟存储库。例如,Spring Framework 大量使用这种模式 接口>> AbstractInterface
public abstract class AbstractRepository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> implements Repository<INSTANCE_CLASS, UPDATABLE_INSTANCE_CLASS, PRIMARY_KEY_CLASS> { public void add(INSTANCE_CLASS instance) { throw new UnsupportedOperationException("Not supported yet."); } public void remove(PRIMARY_KEY_CLASS id) { throw new UnsupportedOperationException("Not supported yet."); } public void update(PRIMARY_KEY_CLASS id, UPDATABLE_INSTANCE_CLASS updatableInstance) { throw new UnsupportedOperationException("Not supported yet."); } public INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id) { throw new UnsupportedOperationException("Not supported yet."); } public INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id, FetchingStrategy fetchingStrategy) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAll() { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAll(FetchingStrategy fetchingStrategy) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAll(int pageNumber, int pageSize, FetchingStrategy fetchingStrategy) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria, FetchingStrategy fetchingStrategy) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria) { throw new UnsupportedOperationException("Not supported yet."); } public List<INSTANCE_CLASS> findAllByCriteria(int pageNumber, int pageSize, Criteria criteria, FetchingStrategy fetchingStrategy) { throw new UnsupportedOperationException("Not supported yet."); } }
因此,您的GiftCardRepository可以重写为(请参见扩展而不是工具),并且 可以覆盖您真正想要的内容
public class GiftCardRepository extends AbstractRepository<GiftCard, GiftCard, String> { public static final GIFT_CARDS_WITH_BUYER GIFT_CARDS_WITH_BUYER = new GIFT_CARDS_WITH_WITH_BUYER(); public static final GIFT_CARDS_WITHOUT_NO_RELATIONSHIP GIFT_CARDS_WITHOUT_NO_RELATIONSHIP = new GIFT_CARDS_WITHOUT_NO_RELATIONSHIP(); public List<GiftCard> findAll(FetchingStrategy fetchingStrategy) { sessionFactory.getCurrentSession().getNamedQuery(fetchingStrategy.toString()).list(); } /** * FetchingStrategy is just a marker interface * public interface FetchingStrategy {} * * And AbstractFetchingStrategy allows you to retrieve the name of the Fetching Strategy you want, by overriding toString method * public class AbstractFetchingStrategy implements FetchingStrategy { * * @Override * public String toString() { * return getClass().getSimpleName(); * } * * } * * Because there is no need to create an instance outside our repository, we mark it as private * Notive each FetchingStrategy must match a named query */ private static class GIFT_CARDS_WITH_BUYER extends AbstractFetchingStrategy {} private static class GIFT_CARDS_WITHOUT_NO_RELATIONSHIP extends AbstractFetchingStrategy {} }
现在,我们将命名查询外部化为多行且可读且可维护的xml文件
// app.hbl.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <query name="GIFT_CARDS_WITH_BUYER"> <![CDATA[ from GiftCard c left join fetch c.buyer where c.recipientNotificationRequested = 1 ]]> </query> <query name="GIFT_CARDS_WITHOUT_NO_RELATIONSHIP"> <![CDATA[ from GiftCard ]]> </query> </hibernate-mapping>
因此,如果您想与买家一起找回GiftCard,只需致电
Repository<GiftCard, GiftCard, String> giftCardRepository; List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITH_WITH_BUYER);
并要获取没有任何关系的GiftCard,只需致电
List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITHOUT_NO_RELATIONSHIP);
或使用import static
import static packageTo.GiftCardRepository.*;
和
List<GiftCard> giftCardList = giftCardRepository.findAll(GIFT_CARDS_WITHOUT_NO_RELATIONSHIP);
希望对您有用!