当前位置: 首页 > 知识库问答 >
问题:

JPA/Hibernate在OneToOne Find上双击

石博艺
2023-03-14

在学习JPA/Hibernate时,我偶然发现了一些意想不到的事情。我得到了一个不必要的对db的双击查询(参见buttom)。我有一个简单的OneToOne设置。

这是我的联系人:

@Entity
@Table(name = "contact")
public class Contact {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "contact_id", nullable = false, insertable = false, updatable = false)
  private Long id;

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

  @OneToOne
  @JoinColumn(name="fk_address_id", referencedColumnName="address_id")
  private Address address;

  public Contact(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  // getters/setters

}

我的地址实体:

@Entity
@Table(name = "address")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "address_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "location", nullable = false)
  private String location;

  @OneToOne(mappedBy = "address")
  private Contact contact;

  public Address(String location) {
    this.location = location;
  }

  // getters/setters

}

这就是我运行代码的方式:

  private EntityManager em;

  @Before
  public void setup() {
    em = EntityManagerFactoryCreator.getEntityManagerFactory().createEntityManager();
  }

  @Test
  public void createContactWithAddress() {
    Address address = new Address("Made");
    Contact contact = new Contact("Jan", address);

    em.getTransaction().begin();
    em.persist(address);
    em.persist(contact);
    em.getTransaction().commit();

    em.close();
    em = EntityManagerFactoryCreator.getEntityManagerFactory().createEntityManager();

    Contact managedContact = em.find(Contact.class, 1L);
  }

}

这可能是愚蠢的事情,但是什么导致了双重选择?

Hibernate: 

    drop table address if exists
Hibernate: 

    drop table book if exists
Hibernate: 

    drop table contact if exists
Hibernate: 

    create table address (
       address_id bigint generated by default as identity,
        location varchar(255) not null,
        primary key (address_id)
    )
Hibernate: 

    create table book (
       book_id bigint generated by default as identity,
        category varchar(255),
        release_date date,
        summary varchar(255),
        title varchar(255) not null,
        primary key (book_id)
    )

Hibernate: 

    create table contact (
       contact_id bigint generated by default as identity,
        name varchar(255) not null,
        address_address_id bigint,
        primary key (contact_id)
    )
Hibernate: 

    alter table book 
       add constraint UK_g0286ag1dlt4473st1ugemd0m unique (title)
Hibernate: 

    alter table contact 
       add constraint FKrc0ixa9b11b9tv3hyq0iwvdpt 
       foreign key (address_address_id) 
       references address
Hibernate: 
    insert 
    into
        address
        (address_id, location) 
    values
        (null, ?)
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [VARCHAR] - [Made]
Hibernate: 
    insert 
    into
        contact
        (contact_id, address_address_id, name) 
    values
        (null, ?, ?)
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [2] as [VARCHAR] - [Jan]
Hibernate: 
    select
        contact0_.contact_id as contact_1_2_0_,
        contact0_.address_address_id as address_3_2_0_,
        contact0_.name as name2_2_0_,
        address1_.address_id as address_1_0_1_,
        address1_.location as location2_0_1_ 
    from
        contact contact0_ 
    left outer join
        address address1_ 
            on contact0_.address_address_id=address1_.address_id 
    where
        contact0_.contact_id=?
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_1_0_1_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_3_2_0_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([name2_2_0_] : [VARCHAR]) - [Jan]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([location2_0_1_] : [VARCHAR]) - [Made]
Hibernate: 
    select
        contact0_.contact_id as contact_1_2_1_,
        contact0_.address_address_id as address_3_2_1_,
        contact0_.name as name2_2_1_,
        address1_.address_id as address_1_0_0_,
        address1_.location as location2_0_0_ 
    from
        contact contact0_ 
    left outer join
        address address1_ 
            on contact0_.address_address_id=address1_.address_id 
    where
        contact0_.address_address_id=?
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_1_0_0_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([contact_1_2_1_] : [BIGINT]) - [1]

注意:My EntityManagerFactoryCreator是调用Persistence.createEntityManagerFactory("nl.infosupport.javaminor.week4.jpa.h2")的单例;

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  version="2.1">

  <persistence-unit name="nl.infosupport.javaminor.week4.jpa.h2">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <properties>
      <property name="javax.persistence.jdbc.user" value="sa"/>
      <property name="javax.persistence.jdbc.password" value="sa"/>
      <property name="javax.persistence.jdbc.url" value="jdbc:h2:~/Documents/InfoSupport-Minor/h2_embedded_db/test"/>
      <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>

      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>

</persistence>

共有1个答案

孙清野
2023-03-14

在这种情况下,这是正常的行为,对于您拥有的表配置来说。如果只想有一个select,则需要使用一个自定义查询连接子表。例如,使用HQL,它看起来是这样的:

    public Contact find(Long id) {
        TypedQuery<Contact> query = em.createQuery(
        "SELECT c FROM Contact c join fetch c.address WHERE c.id = :id", Contact.class);
         return query
           .setParameter("id", id)
           .getSingleResult();
    }

代码不需要工作,我没有调试它,但它显示了原理。

已更新

或者你可以试着像这样注释这个字段

@Fetch(FetchMode.JOIN)
private Address address;

然后它只会触发一个查询。

 类似资料:
  • 拥有2个实体:订单和产品。1个订单可以有多个产品,多个产品可以属于1个订单(每个产品只属于1个订单)。 尝试了@JsonIgnore。这不会返回子元素或父元素。尝试了@JsonManagedReference和@JsonBackReference-仍然没有成功。 请给我指点一下

  • Micronaut/JPA/Hibernate小写了我的数据库表的名称,并在启动时抛出一个错误,说找不到该表。表在那里,但它是用大写字母命名的。我如何配置micronaut/jpa/hibernate来考虑我的表名的大小写 我在MySQL8数据库中有一个现有的表< code >小部件,我需要使用jpa/hibernate从micronaut服务访问它。不幸的是,在启动时的模式验证期间抛出了一个错误

  • 1.JPA 1.1 自动扫描Entity 彻底删除persistence.xml中Entity的逐一配置,采用自动扫描。因为Weblogic/Jboss这些自带JPA支持的应用服务器有时候会多管闲事的扫描persistence.xml,因此彻底删除掉这个文件是个不错的选择。 <bean id="entityManagerFactory" class="org.springframework

  • 问题内容: 据我所知,JPA本身提供了所有闪亮的功能,例如ORM,JPQL,实体关系映射等。但是我真的不明白,为什么人们在JPA之上使用Hibernate或Toplink。 Hibernate提供了JPA本身没有的哪些功能? 问题答案: JPA只是一个规范。Hibernate和TopLink是该规范的实现。 而且,JPA规范有点弱,它仅提供Hibernate和TopLink之类提供的功能的子集。有

  • 我正在开发一个REST应用程序来加载CSV文件,将它们插入数据库(MYSQL-mysqld Ver 5.7.32),然后以JSON格式查询和显示记录。 问题是,当我尝试使用JPA repository SaveAll()方法持久化记录时,需要花费大量时间(500条记录大约25秒)。 我搜索了解决方案,发现一些配置更改似乎可以解决问题,但没有一个对我有帮助。我改变了日志记录。数量组织。冬眠SQL=D

  • 问题内容: 从Tomcat迁移到WebSphere时,我遇到了Spring 4 / Hibernate项目无法正确加载的问题。我已经将应用程序设置为PARENT_LAST类加载器,并将Hibernate版本恢复为4.2.16(由于WAS 8.5.5仅支持JPA 2.0)。我确实必须将WAR封装在EAR内,以符合IDE集成要求。 我现在在启动时遇到以下错误。任何援助将不胜感激。如果有人在WebSph