O que exatamente a estratégia de busca do JPA controla? Não consigo detectar nenhuma diferença entre ansioso e preguiçoso. Em ambos os casos JPA / Hibernate não associa automaticamente relacionamentos muitos para um.
Exemplo: a pessoa possui um único endereço. Um endereço pode pertencer a muitas pessoas. As classes de entidade anotadas JPA se parecem com:
@Entity
public class Person {
@Id
public Integer id;
public String name;
@ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
@Entity
public class Address {
@Id
public Integer id;
public String name;
}
Se eu usar a consulta JPA:
select p from Person p where ...
JPA / Hibernate gera uma consulta SQL para selecionar na tabela Person e, em seguida, uma consulta de endereço distinta para cada pessoa:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
Isso é muito ruim para grandes conjuntos de resultados. Se houver 1000 pessoas ele gera 1001 consultas (1 de Pessoa e 1000 distintas de Endereço). Eu sei disso porque estou olhando o log de consultas do MySQL. Eu entendi que definir o tipo de busca de endereço como ansioso fará com que o JPA / Hibernate consulte automaticamente com uma junção. No entanto, independentemente do tipo de busca, ele ainda gera consultas distintas para relacionamentos.
Somente quando eu digo explicitamente para entrar, ele realmente entra:
select p, a from Person p left join p.address a where ...
Estou faltando alguma coisa aqui? Agora tenho que codificar manualmente cada consulta para que ela se junte aos relacionamentos muitos para um. Estou usando a implementação JPA do Hibernate com MySQL.
Editar: Parece (consulte Hibernate FAQ aqui e aqui ) que FetchType
não afeta as consultas JPA. Portanto, no meu caso, eu disse explicitamente para entrar.
Respostas:
O JPA não fornece nenhuma especificação sobre anotações de mapeamento para selecionar a estratégia de busca. Em geral, as entidades relacionadas podem ser obtidas de qualquer uma das maneiras fornecidas abaixo
Assim
SELECT
eJOIN
são dois extremos eSUBSELECT
caem no meio. Pode-se escolher a estratégia adequada com base em seu modelo de domínio.Por padrão,
SELECT
é usado por JPA / EclipseLink e Hibernate. Isso pode ser substituído usando:em Hibernate. Ele também permite definir o
SELECT
modo explicitamente usando o@Fetch(FetchMode.SELECT)
que pode ser ajustado usando o tamanho do lote, por exemplo@BatchSize(size=10)
.As anotações correspondentes no EclipseLink são:
fonte
"mxc" está certo.
fetchType
apenas especifica quando a relação deve ser resolvida.Para otimizar o carregamento antecipado usando uma junção externa, você deve adicionar
para o seu campo. Esta é uma anotação específica de hibernação.
fonte
O atributo fetchType controla se o campo anotado é buscado imediatamente quando a entidade primária é buscada. Isso não determina necessariamente como a instrução fetch é construída, a implementação real do sql depende do provedor que você está usando toplink / hibernate etc.
Se você definir
fetchType=EAGER
Isso significa que o campo anotado é preenchido com seus valores ao mesmo tempo que os outros campos na entidade. Portanto, se você abrir um gerenciador de entidade, recupere seus objetos pessoais e, em seguida, feche o gerenciador de entidade, subsequentemente, fazer uma pessoa.address não resultará em uma exceção de carregamento lento.Se você definir,
fetchType=LAZY
o campo só será preenchido quando for acessado. Se você tiver fechado o entitymanager até então, uma exceção de carregamento lento será lançada se você fizer um person.address. Para carregar o campo, você precisa colocar a entidade de volta em um contexto de gerenciadores de entidades com em.merge (), acessar o campo e fechar o gerenciador de entidades.Você pode desejar o carregamento lento ao construir uma classe de cliente com uma coleção para pedidos de cliente. Se você recuperou todos os pedidos de um cliente quando queria obter uma lista de clientes, esta pode ser uma operação de banco de dados cara quando você procura apenas o nome do cliente e detalhes de contato. Melhor deixar o acesso db para mais tarde.
Para a segunda parte da pergunta - como hibernar para gerar SQL otimizado?
O Hibernate deve permitir que você forneça dicas de como construir a consulta mais eficiente, mas suspeito que haja algo errado com a construção da sua tabela. A relação é estabelecida nas tabelas? O Hibernate pode ter decidido que uma consulta simples será mais rápida do que uma junção, especialmente se os índices etc. estiverem ausentes.
fonte
Experimente com:
Ele funciona para mim de maneira semelhante ao JPA2 / EclipseLink, mas parece que esse recurso também está presente no JPA1 :
fonte
Se você usar o EclipseLink em vez do Hibernate, você pode otimizar suas consultas por "dicas de consulta". Consulte este artigo do Eclipse Wiki: EclipseLink / Examples / JPA / QueryOptimization .
Há um capítulo sobre "Leitura conjunta".
fonte
para participar, você pode fazer várias coisas (usando eclipselink)
em jpql você pode fazer busca de junção à esquerda
na consulta nomeada, você pode especificar a dica da consulta
em TypedQuery você pode dizer algo como
query.setHint("eclipselink.join-fetch", "e.projects.milestones");
há também uma dica de busca em lote
query.setHint("eclipselink.batch", "e.address");
Vejo
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
fonte
Eu tive exatamente esse problema com a exceção de que a classe Person tinha uma classe de chave incorporada. Minha própria solução foi juntá-los na consulta E remover
@Fetch(FetchMode.JOIN)
Minha classe de id incorporada:
fonte
Duas coisas me ocorrem.
Primeiro, você tem certeza de que quer dizer ManyToOne para endereço? Isso significa que várias pessoas terão o mesmo endereço. Se for editado para um deles, será editado para todos eles. É essa a sua intenção? 99% das vezes os endereços são "privados" (no sentido de que pertencem a apenas uma pessoa).
Em segundo lugar, você tem algum outro relacionamento ativo na entidade Person? Se bem me lembro, o Hibernate só pode lidar com um relacionamento ansioso em uma entidade, mas essa informação possivelmente está desatualizada.
Digo isso porque sua compreensão de como isso deve funcionar está essencialmente correta de onde estou sentado.
fonte