Ben*_*son 5 hibernate hql criteria lazy-evaluation
我在优化Hibernate查询时遇到问题,以避免执行连接或二次选择.
执行Hibernate查询(条件或hql)时,如下所示:
return getSession().createQuery(("from GiftCard as card where card.recipientNotificationRequested=1").list();
Run Code Online (Sandbox Code Playgroud)
...和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;
}
}
Run Code Online (Sandbox Code Playgroud)
正如所说
我想要一个解决方案,可以控制执行查询时延迟加载的内容
如果您有这样的映射
@Entity
public class GiftCard implements Serializable {
private User buyer;
@ManyToOne
@JoinColumn(name="buyerUserId")
public User getBuyer() {
return this.buyer;
}
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,任何 *ToOne 关系(例如 @OneToOne 和 @ManyToOne)都是 FetchType.EAGER,这意味着它将始终被获取。但是,这不可能是你想要的。你所说的我可以控制延迟加载的内容可以翻译为获取策略。《POJO in Action》一书支持这样的模式(注意方法签名)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,根据您的用例,您可以创建自己的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);
}
Run Code Online (Sandbox Code Playgroud)
但是,有时,您不希望通用存储库接口定义所有方法。解决方案:创建一个 AbstractRepository 类,它将实现一个虚拟存储库。例如,Spring 框架大量使用这种模式Interface >> 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.");
}
}
Run Code Online (Sandbox Code Playgroud)
因此,您的 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 {}
}
Run Code Online (Sandbox Code Playgroud)
现在,我们将命名查询外部化到一个多行且可读且可维护的 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>
Run Code Online (Sandbox Code Playgroud)
因此,如果您想向买家取回礼品卡,只需致电
Repository<GiftCard, GiftCard, String> giftCardRepository;
List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITH_WITH_BUYER);
Run Code Online (Sandbox Code Playgroud)
要在没有任何关系的情况下取回我们的礼品卡,只需致电
List<GiftCard> giftCardList = giftCardRepository.findAll(GiftCardRepository.GIFT_CARDS_WITHOUT_NO_RELATIONSHIP);
Run Code Online (Sandbox Code Playgroud)
或使用导入静态
import static packageTo.GiftCardRepository.*;
Run Code Online (Sandbox Code Playgroud)
和
List<GiftCard> giftCardList = giftCardRepository.findAll(GIFT_CARDS_WITHOUT_NO_RELATIONSHIP);
Run Code Online (Sandbox Code Playgroud)
我希望它对你有用!
| 归档时间: |
|
| 查看次数: |
7331 次 |
| 最近记录: |