Hibernate:如何急切地获取未关联的实体?

时间:2009-09-23 17:13:47

标签: java hibernate caching prefetch

Java Persistence with Hibernate显示了许多关于如何热切地获取关联的实体的示例,例如:

  • 将@ org.hibernate.annotations.BatchSize添加到关联的类
  • 将@ org.hibernate.annotations.Fetch添加到引用关联类的字段
  • 在HQL查询等中使用“fetch”关键字......

但是在我的情况下,我正在处理一个运行缓慢的过程,该过程负责构建与感兴趣的实体类的关联。这意味着 - 在执行时 - 我无法查询一个实体并要求它急切地获取另一个实体的所有相关实例,因为不存在这样的关联。

换句话说,过程看起来像这样:

public class InitConfig {

    private final SessionFactory sessionFactory;
    private final NodeManager nodeManager;

    public void run() {

        final Configuration config = new Configuration("NewConfiguration", new HashSet<Node> ());
        for(String name : lotsOfNames) {

            //Lots of these queries run slowly
            final Node node = this.nodeManager.getNode(name);
            config.addNode(node);
        }
        this.sessionFactory.getCurrentSession().save(config);
    }
}

相关的DAO(NodeManager)和慢速查询实体(Node)如下所示:

public class NodeManager {

    private final SessionFactory sessionFactory;

    public Node getNode(String name) {

        final Session db = this.sessionFactory.getCurrentSession();
        final Query query = db.createQuery("from NODE where NAME = :name");
        query.setString("name", name);
        return (Node)query.uniqueResult();
    }
}

@Entity(name="NODE")
public class Node {

    @GeneratedValue(strategy=GenerationType.TABLE)
    @Id @Column(name="ID")
    private Long id;

    private @Column(name="NAME", nullable=false, unique=true) String name;

    //Other properties and associations...
}

最后,由缓慢运行的进程创建的实体:

@Entity(name="CONFIGURATION")
public class Configuration {

    @Id @GeneratedValue @Column(name="ID")
    private Long id;
    private @Column(name="NAME", nullable=false, unique=true) String name;

    @ManyToMany
    @JoinTable(
        name="CONFIGURATION_NODE",
        joinColumns=@JoinColumn(name="CONFIGURATION_ID", nullable=false),
        inverseJoinColumns=@JoinColumn(name="NODE_ID", nullable=false))
    private Set<Node> nodes = new HashSet<Node> ();

    public void addNode(Node node) {

        this.nodes.add(node);
    }
}

我的问题是:如何修改Hibernate配置和/或代码,以便一次急切地获取Node的许多实例?

关注的问题是:

  • Hibernate的二级缓存是否适用于此,如果是,我该如何配置?
  • 如果没有,是否还有其他一些可以在这里使用的Hibernate功能?

目前大约有100,000个节点,所以我不愿意采用强力方法查询每个节点并将其缓存在应用程序的某个地方,因为这不会扩展到更高数量的节点,看起来像它会在应用程序和Hibernate的内部(会话,二级缓存等)之间复制数据。

1 个答案:

答案 0 :(得分:2)

我不是100%明白你在这里要做什么...... Configuration.addNode()(或其他一些你未展示的方法)是否涉及一些商业逻辑?

如果没有,那么运行多个批量更新查询以将节点与配置相关联可能会好得多。

如果确实(意味着您必须加载并检查每个节点),您可以:

  1. 将整个lotsOfNames列表拆分为1000个名称(您可以使用此数字来查看最佳性能)。
  2. 通过name IN(?)条件查询,立即加载整批节点。
  3. 将它们添加到您的配置中。
  4. 刷新会话(并且,可选地,提交/启动新事务)。
  5. 应该快得多,因为您将执行1次查询而不是1000次并将插入内容组合在一起。