2017-02-17 11 views
0

Ну, есть много вопросов именно с этим названием, но ни один из них не имеет правильных ответов или они не совсем такие же, как у меня.JPA/Hibernate FetchType.LAZY не работает

У меня есть две сущности:

Person:

@Entity 
@Table(name = "Person") 
@Inheritance(strategy = InheritanceType.JOINED) 
@Access(AccessType.FIELD) 
public class Person { 

    @Id 
    @GeneratedValue 
    private Long id; 

    @Column(name = "firstname") 
    private String firstName; 

    @Column(name = "lastname", length = 100, nullable = false, unique = false) 
    private String lastName; 

    @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.MERGE, mappedBy="owner") 
    private Set<Car> cars; 

    public Long getId() { 

     return id; 
    } 

    public void setId(Long id) { 

     this.id = id; 
    } 

    public String getFirstName() { 

     return firstName; 
    } 

    public void setFirstName(String firstName) { 

     this.firstName = firstName; 
    } 

    public String getLastName() { 

     return lastName; 
    } 

    public void setLastName(String lastName) { 

     this.lastName = lastName; 
    } 

    public Set<Car> getCars() { 

     return cars; 
    } 

    public void setCars(Set<Car> cars) { 

     this.cars = cars; 
    } 

    @Override 
    public String toString() { 

     return String.format("(%d, %s, %s)",id, firstName, lastName); 
    } 
} 

и автомобиль:

@Entity 
@Table(name = "Car") 
@Inheritance(strategy = InheritanceType.JOINED) 
@Access(AccessType.FIELD) 
public class Car { 

    @Id 
    @GeneratedValue 
    private Long id; 

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.MERGE) 
    @JoinColumn(name="id_person", columnDefinition="BIGINT") 
    private Person owner; 

    @Column(name="name") 
    private String name; 

    @Column(name="model") 
    private String model; 

    public Long getId() { 

     return id; 
    } 

    public void setId(Long id) { 

     this.id = id; 
    } 

    public Person getOwner() { 

     return owner; 
    } 

    public void setOwner(Person owner) { 

     this.owner = owner; 
    } 

    public String getName() { 

     return name; 
    } 

    public void setName(String name) { 

     this.name = name; 
    } 

    public String getModel() { 

     return model; 
    } 

    public void setModel(String model) { 

     this.model = model; 
    } 

    @Override 
    public String toString() { 

     return String.format("(%d, %s, %s, %s)", id, name, model, owner); 
    } 
} 

Также я определил ограничения внешнего ключа в моей базе данных Mysql между Person и таблицей автомобилей на столбце id_person

Мой файл persistence.xml выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8" ?> 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> 

    <persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL"> 

     <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 

     <properties> 
      <!-- Configuring JDBC properties --> 
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/hibernatedb" /> 
      <property name="javax.persistence.jdbc.user" value="root" /> 
      <property name="javax.persistence.jdbc.password" value="DA_PASSWORD" /> 
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> 

      <!-- Hibernate properties --> 
      <property name="hibernate.show_sql" value="true" /> 
      <property name="hibernate.format_sql" value="true" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> 
      <property name="hibernate.hbm2ddl.auto" value="validate" /> 

      <!-- Configuring Connection Pool --> 
      <property name="hibernate.c3p0.min_size" value="5" /> 
      <property name="hibernate.c3p0.max_size" value="20" /> 
      <property name="hibernate.c3p0.timeout" value="500" /> 
      <property name="hibernate.c3p0.max_statements" value="50" /> 
      <property name="hibernate.c3p0.idle_test_period" value="2000" /> 
     </properties> 
    </persistence-unit> 
</persistence> 

Внутри моего кода, я пытаюсь выбрать Автомобили, используя критерии запроса следующим образом:

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Car> q = cb.createQuery(Car.class); 
Root<Car> root = q.from(Car.class); 

q.select(root); 

Когда я получаю результаты и распечатать их

TypedQuery<Car> typedQuery = entityManager.createQuery(q); 
List<Car> cars = typedQuery.getResultList(); 
log.info("*****************************{}", cars); 

К моему удивлению, он печатает :

*****************************[(1, Hiundai, 2016, (1, Homer1530962140, Simpson)), (2, Benz, 2016, (1, Homer1530962140, Simpson)), (3, Benz, 
2017, (2, Homer12935192, Simpson))] 

Это означает, что для каждого автомобильные принадлежности, владельцы охотно тоже были взяты!

Вот журналы запрос к базе данных:

2017-02-17T14:02:58.324926Z 391 Query /* mysql-connector-java-5.1.13 (Revision: ${bzr.revision-id}) */SELECT @@session.auto_increment_increment 
2017-02-17T14:02:58.325405Z 391 Query SHOW COLLATION 
2017-02-17T14:02:58.335552Z 391 Query SET NAMES latin1 
2017-02-17T14:02:58.335772Z 391 Query SET character_set_results = NULL 
2017-02-17T14:02:58.336160Z 391 Query SET autocommit=1 
2017-02-17T14:02:58.336349Z 391 Query SET autocommit=0 
2017-02-17T14:02:58.720821Z 391 Query SHOW FULL TABLES FROM `hibernatedb` LIKE 'Car' 
2017-02-17T14:02:58.724527Z 391 Query SHOW FULL TABLES FROM `hibernatedb` LIKE 'Car' 
2017-02-17T14:02:58.725337Z 391 Query SHOW FULL COLUMNS FROM `Car` FROM `hibernatedb` LIKE '%' 
2017-02-17T14:02:58.729899Z 391 Query SHOW FULL TABLES FROM `hibernatedb` LIKE 'Person' 
2017-02-17T14:02:58.730468Z 391 Query SHOW FULL TABLES FROM `hibernatedb` LIKE 'Person' 
2017-02-17T14:02:58.730887Z 391 Query SHOW FULL COLUMNS FROM `Person` FROM `hibernatedb` LIKE '%' 
2017-02-17T14:02:59.022835Z 391 Query select car0_.id as id1_0_, car0_.model as model2_0_, car0_.name as name3_0_, car0_.id_person as id_perso4_0_ from Car car0_ 
2017-02-17T14:02:59.041016Z 391 Query SHOW WARNINGS 
2017-02-17T14:02:59.045266Z 391 Query select person0_.id as id1_1_0_, person0_.firstname as firstnam2_1_0_, person0_.lastname as lastname3_1_0_ from Person person0_ where person0_.i 
d=1 
2017-02-17T14:02:59.059184Z 391 Query SHOW WARNINGS 
2017-02-17T14:02:59.064163Z 391 Query select person0_.id as id1_1_0_, person0_.firstname as firstnam2_1_0_, person0_.lastname as lastname3_1_0_ from Person person0_ where person0_.i 
d=2 
2017-02-17T14:02:59.065827Z 391 Query SHOW WARNINGS 
2017-02-17T14:02:59.070262Z 391 Query rollback 
2017-02-17T14:02:59.070468Z 391 Quit 

Совершенно очевидно, что отдельный запрос выдается, чтобы получить информацию о человеке, а я, кажется, не спросить такую ​​вещь в моем коде.

Почему это происходит?

ответ

2

Вы запросили информацию о владельце, когда вы преобразовали автомобиль в строку.

@Override 
public String toString() { 

    return String.format("(%d, %s, %s, %s)", id, name, model, owner); 
} 

В этот момент ему необходимо было восстановить владельца для выполнения команды toString().

+0

Спасибо @ Джон Холмер.Я сам думал об этой части кода, но, честно говоря, мне трудно понять, как JPA может обнаружить доступ к зарегистрированной сущности и создать запрос на основе этого. – madz

2
log.info("*****************************{}", cars); 

При выполнении этого:

  1. рамки Logging называет toString() в списке
  2. toString() вызывается на каждом методе класса автомобиля Car
  3. toString называет toString() метод Person класса , И это та часть, где происходит «волшебство». Оказывается, что Hibernate использует сгенерированные прокси-классы для обеспечения ленивой загрузки для некоторых ассоциаций (один к одному, много-к-одному). Другими словами, Hibernate инициализирует поле Car.owner со ссылкой на прокси-класс, который расширяет класс Person. Этот прокси-класс содержит дополнительную логику, которая обрабатывает ленивую загрузку.
+0

+1 для более подробной информации. Я несколько раз искал, как спящий режим может перехватывать доступ к полю с помощью javassist – madz

Смежные вопросы