Hibernate JPA:在获取单个记录@OneToOne和@PrimaryKeyJoinColumn时,有多个select语句
将我的实体视为CPU和处理器,具有一对一的关系和共享主键。 一个CPU有一个处理器 javaHibernate JPA:在获取单个记录@OneToOne和@PrimaryKeyJoinColumn时,有多个select语句,hibernate,jpa,Hibernate,Jpa,将我的实体视为CPU和处理器,具有一对一的关系和共享主键。 一个CPU有一个处理器 java @Entity @Table(name = "PKJoin_CPUt") public class CPU { private int id; private String name; private Processor processor; @OneToOne(cascade = CascadeType.PERSIST, mappedBy = "cpu", opt
@Entity
@Table(name = "PKJoin_CPUt")
public class CPU {
private int id;
private String name;
private Processor processor;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy = "cpu", optional = true,fetch=FetchType.LAZY)
public Processor getProcessor() {
return processor;
}
public void setProcessor(Processor processor) {
this.processor = processor;
if (null != processor) {
processor.setCpu(this);
}
}
private Processor2 processor2;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy = "cpu", optional = true,fetch=FetchType.LAZY)
public Processor2 getProcessor2() {
return processor2;
}
public void setProcessor2(Processor2 processor2) {
this.processor2 = processor2;
if (null != processor2) {
processor2.setCpu(this);
}
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
if (null != processor) {
processor.setId(id);
}
if (null != processor2) {
processor2.setId(id);
}
}
public String getName() {
return name;
}
public void setName(String deptName) {
this.name = deptName;
}
}
Processor.java
@Entity
@Table(name = "PKJoin_Processor")
public class Processor {
private int id;
private String name;
private CPU cpu;
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
public CPU getCpu() {
return cpu;
}
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main.java
public class Main {
static EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
static EntityManager em = emf.createEntityManager();
public static void main(String[] a) throws Exception {
em.getTransaction().begin();
new Main().findData();
// new Main().persistData();
em.getTransaction().commit();
em.close();
emf.close();
}
public void findData(){
CPU cpu = em.find(CPU.class, 449);
System.out.println(cpu.getProcessor().getName());
}
}
这是这样执行的::
Hibernate: select cpu0_.id as id11_0_, cpu0_.name as name11_0_ from PKJoin_CPUt cpu0_ where cpu0_.id=?
Hibernate: select processor0_.id as id38_0_, processor0_.name as name38_0_ from PKJoin_Processor processor0_ where processor0_.id=?
Hibernate: select processor2x0_.id as id19_0_, processor2x0_.name as name19_0_ from PKJoin_Processor222 processor2x0_ where processor2x0_.id=?
乔
我不希望在仅获取CPUName属性时执行这三个查询。我也不希望join。
每当我试图获取CPU属性时,我只希望执行第一个查询。
需要解决方案吗?问题在于,由于关联是可选的,Hibernate无法通过加载CPU来知道它是否有关联的处理器。因此,为了将processor字段设置为null,或者将其设置为processor实例,必须检查是否存在具有CPU主键的处理器 为了避免这种情况,最简单的方法是使用CPU中指向处理器的连接列映射关联。这样,如果join列为null,Hibernate就知道没有关联的CPU。如果不为null,它可以将prossor字段设置为惰性代理
另一种方法,AFAIK,是使用
@LazyToOne(无代理)
,并执行以下操作。但我过去在这种环境下有过不好的经历。可能它有所改进。问题在于,由于关联是可选的,Hibernate无法通过加载CPU来知道它是否有关联的处理器。因此,为了将processor字段设置为null,或者将其设置为processor实例,必须检查是否存在具有CPU主键的处理器
为了避免这种情况,最简单的方法是使用CPU中指向处理器的连接列映射关联。这样,如果join列为null,Hibernate就知道没有关联的CPU。如果不为null,它可以将prossor字段设置为惰性代理
另一种方法,AFAIK,是使用@LazyToOne(无代理)
,并执行以下操作。但我过去在这种环境下有过不好的经历。也许它已经改进了。在findData()中,您需要执行cpu.getProcessor().getName(),因此,查询第一个处理器是合乎逻辑的
你在CPU.setId()函数中做了一些奇怪的事情,也许这就是为什么要加载处理器
你不应该这样做,你应该让hibernate来处理。对于基于主键的双向一对一关系,我认为您需要:
public class CPU {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "cpu", fetch=FetchType.LAZY)
private Processor processor;
...
}
public class Processor {
@Id @OneToOne
@JoinColumn("id")
private CPU cpu; //combine @Id and @OneToOne, no int id needed.
protected Processor(){}
public Processor(CPU cpu){
this.cpu = cpu;
cpu.setProcessor(this);
}
...
}
现在,如果你用一个CPU保存一个处理器,它的id会神奇地用CPU的id填充。
确保按正确的顺序保存它们:
CPU cpu = new CPU();
em.save(cpu);
Processor p = new Processor(cpu);
em.save(p);
在findData()中,需要执行cpu.getProcessor().getName(),因此逻辑上可以得到第一个处理器的查询
你在CPU.setId()函数中做了一些奇怪的事情,也许这就是为什么要加载处理器
你不应该这样做,你应该让hibernate来处理。对于基于主键的双向一对一关系,我认为您需要:
public class CPU {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "cpu", fetch=FetchType.LAZY)
private Processor processor;
...
}
public class Processor {
@Id @OneToOne
@JoinColumn("id")
private CPU cpu; //combine @Id and @OneToOne, no int id needed.
protected Processor(){}
public Processor(CPU cpu){
this.cpu = cpu;
cpu.setProcessor(this);
}
...
}
现在,如果你用一个CPU保存一个处理器,它的id会神奇地用CPU的id填充。
确保按正确的顺序保存它们:
CPU cpu = new CPU();
em.save(cpu);
Processor p = new Processor(cpu);
em.save(p);
但是Nizet先生,你不认为@JoinColumn会在两边创建一个新的额外列吗。我的情况如下:但是Nizet先生,你不认为@JoinColumn会在两边创建一个新的额外列吗。我的情况如下:1。CPU有处理器1,CPU有处理器2。2.我希望CPU的PK变成FK是Processor1和Processor2,并且两边都没有额外的连接列。我也使用上面的代码实现了这一点,但我的问题是,每当我尝试只加载CPU时,它会自动加载Processor1和Processor2,这在性能优化方面是浪费时间的。所以我把重点放在避免它上@LazyToOne(NO_PROXY)在我的案例中也不起作用。有什么方法可以这样做吗?是的,当然它会添加一列。但它将避免额外的查询。确定你觉得最烦人的是什么:增加一个列,还是增加一个查询。但是Nizet先生,你不认为@JoinColumn会在两边创建一个新的额外列吗。我的情况如下:但是Nizet先生,你不认为@JoinColumn会在两边创建一个新的额外列吗。我的情况如下:1。CPU有处理器1,CPU有处理器2。2.我希望CPU的PK变成FK是Processor1和Processor2,并且两边都没有额外的连接列。我也使用上面的代码实现了这一点,但我的问题是,每当我尝试只加载CPU时,它会自动加载Processor1和Processor2,这在性能优化方面是浪费时间的。所以我把重点放在避免它上@LazyToOne(NO_PROXY)在我的案例中也不起作用。有什么方法可以这样做吗?是的,当然它会添加一列。但它将避免额外的查询。决定你觉得最烦人的是什么:增加一个列,还是增加一个查询。