Hibernate выполняет нежелательные SELECT при вызове saveOrUpdate - PullRequest
0 голосов
/ 05 января 2011

Допустим, у меня есть сущность Дома, которая отображается на множество сущностей Лица.Затем я загружаю существующий дом, в котором 20 человек.

beginTransaction();
House house = houseDao.find(1L);
commitTransaction();

Позже в коде я могу добавить нового человека в дом:

...
List<Person> people = house.getPeople();
people.add(new Person("Dilbert"));
....

Когда я звоню:

session.saveOrUpdate(house);

Hibernateвыполняет 21 запрос: 1, чтобы выбрать дом, и 20, чтобы выбрать каждого существующего человека в доме.

Я уверен, что это небольшая проблема с моей стороны, однако, что я должен сделать, чтобы я мог добавитьнового человека в доме, не получившего такого сильного удара по базе данных в этой ситуации?

Все это делается в одном сеансе.

Ответы [ 2 ]

3 голосов
/ 05 января 2011

Поскольку вы действительно не дали много информации об определении ваших объектов, я собираюсь сделать некоторые предположения.

  1. Дом к человеку - один ко многим
  2. Человек можетпринадлежат только одному дому

Убедитесь, что дом определен следующим образом:

@Entity
public class House implements Serializable {
    @Id
    private int id;

    @OneToMany(mappedBy="house")
    private Set<Person> people;

    ... rest of your class
}


@Entity
public class Person implements Serializable {

    @Id
    private int id;

    @ManyToOne(targetEntity=House.class)
    private House house;

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

    ... rest of your class

    public Person(House house, String name) {
       this.house = house;
       this.name = name;
    }
}

Теперь ваш код:

beginTransaction();
House house = houseDao.find(1L);
commitTransaction()


... your magic

Person person = new Person(house,"Dilbert");

session.saveOrUpdate(person);

В приведенном выше примере, когдавы работаете с отношениями Родитель / Ребенок (не важно, один это для многих или многие для многих), вы можете установить отношения через ребенка.Я обычно держусь подальше от просто делать общие обновления через родителя.В вашем примере вы видите, что много над головой.Когда вы начинаете работать там, где есть тысячи записей, это становится невозможным.

Еще одна вещь, на которую стоит обратить внимание, в зависимости от вашей модели, вносит небольшие изменения в аннотации к вашим спискам.Пример:

@Entity
public class House implements Serializable {
    @Id
    private int id;

    @OneToMany(mappedBy="house")
    @Fetch(FetchMode.JOIN)
    private Set<Person> people;

    ... rest of your class
}

Учитывая, что @Fetch не является частью спецификации JPA, а представляет собой аннотацию гибернации, это, в зависимости от вашей модели, может значительно повысить производительность, поскольку захватит объект дома и вселюди в одном запросе.Это очень эффективно, если вы ограничиваете количество домов и людей, которые принадлежат к дому.Если вы получаете очень большие наборы результатов, это может быть не очень хорошая ситуация.Следующий пример может быть более подходящим:

@Entity
public class House implements Serializable {
    @Id
    private int id;

    @OneToMany(mappedBy="house")
    @Fetch(FetchMode.SUBSELECT)
    private Set<Person> people;

    ... rest of your class
}

Это будет использовать два запроса для захвата всех объектов.Один запрос для объекта Дома (или умножение объектов дома в зависимости от запроса) и Один запрос для всех людей для объекта (ов) дома.

0 голосов
/ 05 января 2011

Я думаю, что это потенциальный ответ на вашу проблему, но, возможно, не совсем так, как вы думаете.

Я не нашел способа заставить Hibernate вести себя так, как вы хотите (это не так)такой уровень детализации).Я уверен, что вы могли бы написать это самостоятельно, если хотите.Но если вас действительно беспокоит снижение производительности БД, решите проблему и сконцентрируйтесь на том, как минимизировать нагрузку на БД.

Лучший способ оптимизировать вызовы из Hibernate на БД - этоубедитесь, что все таблицы объектов Hibernate проиндексированы.Hibernate вызывает таблицу, используя первичный ключ родительского объекта.Эти 20 запросов будут занимать очень мало времени на обработку БД, если они попадут в индекс и будут расположены быстро.БД созданы для обработки большого количества транзакций, подобных этой - дорогая часть - найти данные на диске и загрузить их для вашего использования.

Наконец, я бы также добавил кэш объектов.Это может потенциально исключить возможность обращения к БД и сэкономить вашей программе много времени ожидания ввода-вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...