Java Hibernate:如何急切地获取未关联的实体?
Java Persistence with Hibernate展示了许多如何急切获取关联实体的示例,例如:Java Hibernate:如何急切地获取未关联的实体?,java,hibernate,caching,prefetch,Java,Hibernate,Caching,Prefetch,Java Persistence with Hibernate展示了许多如何急切获取关联实体的示例,例如: 将@org.hibernate.annotations.BatchSize添加到关联类 将@org.hibernate.annotations.Fetch添加到引用关联类的字段 在HQL查询中使用“fetch”关键字等 然而,在我的例子中,我正在处理一个运行缓慢的进程,该进程负责建立与感兴趣的实体类的关联。这意味着——在执行时——我不能查询一个实体并要求它急切地获取另一个实体的所有关联
- 将@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);
}
}
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);
}
}
@实体(name=“配置”)
公共类配置{
@Id@GeneratedValue@Column(name=“Id”)
私人长id;
private@Column(name=“name”,nullable=false,unique=true)字符串名;
@许多
@可接合(
name=“配置节点”,
joinColumns=@JoinColumn(name=“CONFIGURATION\u ID”,nullable=false),
inverseJoinColumns=@JoinColumn(name=“NODE_ID”,nullable=false))
私有集节点=新HashSet();
公共void addNode(节点){
this.nodes.add(节点);
}
}
我的问题是:如何修改Hibernate配置和/或代码,以便一次获取多个节点实例
接下来的问题是:
- Hibernate的二级缓存是否适用于此,如果适用,如何配置它
- 如果没有,这里是否可以使用其他Hibernate功能
目前大约有100000个节点,因此我不愿意采用蛮力方法来查询每个节点并将其缓存在应用程序中的某个位置,因为这不会扩展到更高数量的节点,而且似乎会在应用程序和Hibernate的内部之间复制数据(会话、二级缓存等…)我不是100%清楚您在这里试图做什么…Configuration.addNode()(或您未显示的其他方法)是否涉及一些业务逻辑 如果没有,那么最好运行几个批处理更新查询,将节点与配置关联起来 如果确实如此(意味着您必须加载和检查每个节点),您可以:
lotsOfNames
列表拆分为成批,比如1000个名称(您可以使用这个数字来查看什么可以提供最佳性能)name,一次加载整批节点
应该快得多,因为您将执行1个查询,而不是1000个查询,并将插入内容批处理在一起。Configuration.addNode()只调用Configuration.nodes.add(Node)。除了在
lotsOfNames
中可能有一些名称没有匹配的节点外,实际上没有太多的业务逻辑。批更新查询方法听起来是个好主意。如果我向它传递可能不存在的节点名称,这仍然有效吗?是的,非常有效。插入配置节点(配置ID,节点ID)选择:configurationId,ID from NODE where NAME in(:NAME)
。您需要将其作为本机SQL运行,并且仍然需要将大列表拆分为1000个左右的批(除非您首先从某个表中获取它,在这种情况下,您可以在此查询中加入它)谢谢!在本机SQL中使用批处理更新比我以前使用的方法快得多。我很想知道是否有HQL版本的本机SQL更易于移植,但目前还可以。您仍然可以将本机SQL定义为命名查询,并使用Hibernate工具执行它(也许您已经这样做了)。只要您坚持使用标准SQL,它就可以进行移植:-)您不能在HQL中这样做,因为您的关联表在Hibernate眼中不是一等公民;因此,不允许对其进行插入。