Conhecendo o LazyCollectionOption.EXTRA
Mas o de maior interesse é o valor LazyCollectionOption.EXTRA. Se você especificá-lo como o valor da anotação @LazyCollection , o Hibernate atrasará o carregamento dos elementos da coleção pelo maior tempo possível.
Se você tentar obter o número de elementos em uma coleção:
User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
int count = commetns.size();
Então, para todo esse código, o Hibernate executará apenas uma consulta:
SELECT COUNT(id) FROM comment WHERE user_id = 1;
No entanto, se você deseja obter um comentário da coleção, por exemplo, o número 3:
User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
Comment comment = commetns.get(3);
Então surge a pergunta: como o Hibernate deve saber que o elemento é o terceiro sem carregar todos os elementos na memória?
Para resolver este problema, propõe-se criar uma coluna adicional na tabela de comentários, que armazenará o número ordinal do comentário na coleção de comentários. E também para isso você precisa de uma anotação especial - @OrderColumn .
Veja como ficaria essa solução:
@Entity
@Table(name=”user”)
class User {
@Column(name=”id”)
public Integer id;
@OneToMany(cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.EXTRA)
@OrderColumn(name = "order_id")
public List<Comment> comments;
}
A principal vantagem de LazyCollectionOption.EXTRA
Vemos a maior vantagem de LazyCollectionOption.EXTRA quando o especificamos com a anotação @ManyToMany . Vamos pegar nosso antigo caso onde temos um Funcionário, uma Tarefa e podemos atribuir muitas tarefas a um usuário.
Nossas classes Java ficam assim:
Classe de funcionário :
@Entity
@Table(name=”employee”)
class Employee {
@Column(name=”id”)
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="employee_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
@LazyCollection(LazyCollectionOption.EXTRA)
private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}
E a classe EmployeeTask :
@Entity
@Table(name=”task”)
class EmployeeTask {
@Column(name=”id”)
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="task_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
@LazyCollection(LazyCollectionOption.EXTRA)
private Set<Employee> employees = new HashSet<Employee>();
}
E para adicionar uma tarefa ao diretor, você precisa escrever algo como este código:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Portanto, se o campo Employees na classe Task tiver a anotação LazyCollectionOption.EXTRA, a coleção Employees (da classe Task) e a coleção Task (da classe Employee) nunca serão carregadas do banco de dados .
Quando este código for executado, apenas um registro será inserido na tabela de serviço employee_task, que, como você deve se lembrar, é mais ou menos assim:
tabela empregado_tarefa :ID do Empregado | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
4 | 101 |
A linha adicionada é destacada em verde. Para adicionar esta linha, você não precisa carregar coleções do banco de dados - o Hibernate fará sem isso. Este é exatamente o caso quando LazyCollectionOption.EXTRA acelera muito o trabalho com o banco de dados.
N+1 problema
Mas, claro, esse modo também tem uma desvantagem. Por exemplo, a anotação LazyCollectionOption.EXTRA gera um Problema N+1 .
Se você decidir passar por todos os comentários do usuário:
User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
for (Comment comment : comments) {
System.out.println(comment);
}
Então o Hibernate irá executar uma requisição separada para cada objeto Comment. E também mais uma consulta adicional para obter a contagem de todos os comentários. Isso pode tornar o código significativamente mais lento.
Se o seu usuário tiver 1000 comentários, o Hibernate fará 1001 consultas ao banco de dados para executar este código, embora possa fazer com um. Se você soubesse com antecedência que precisaria de todos os objetos desta classe.
GO TO FULL VERSION