O Mybatis fornece funções de consulta de associação avançada, que podem mapear facilmente os conjuntos de resultados obtidos pelo banco de dados para feijões Java definidos. A seguir, é apresentado um exemplo para mostrar como o Mybatis lida com mapeamentos complexos de relacionamento comuns e muitos para um.
Projete um sistema de blog simples em que um usuário possa abrir vários blogs, postar artigos no blog, permitir comentários e marcar artigos. O sistema de blogs consiste principalmente nas seguintes tabelas:
Tabela de autores: tabela de informações do autor, registre as informações do autor, nome de usuário e senha, endereço de e -mail etc.
Tabela de blog: a mesa do blog, um autor pode abrir vários blogs, ou seja, a relação entre autor e blog é um para muitos.
Tabela de postagem: tabela de registro do artigo, gravação do pós -publicação, título, texto e outras informações; Pode haver muitos artigos em um blog, e o relacionamento entre o blog e a postagem é um para muitos.
Tabela de comentários: Tabela de comentários do artigo, comentários do artigo, um artigo pode ter muitos comentários: a correspondência entre postagem e comentários é um para muitos.
Tabela de tag: tabela de tags, que representa a classificação de tags do artigo. Um artigo pode ter várias tags e uma tag pode ser aplicada a diferentes artigos, portanto, a relação entre tag e postagem é um relacionamento de muitos para muitos; (A relação muitos para muitos entre tag e postagem é refletida através da tabela post_tag)
Tabela post_tag: registra a correspondência entre artigos e tags.
De um modo geral, criaremos um Javabean correspondente (ou POJO) com base na estrutura de cada tabela para concluir a operação básica do CRUD da tabela.
A definição de Javabean acima de uma única tabela às vezes não pode atender às necessidades de negócios. Nos negócios, um objeto de blog deve ter informações sobre seu autor e uma lista de artigos, conforme mostrado na figura abaixo:
Se você deseja obter uma instância dessa classe, precisa de pelo menos algumas etapas:
1. Consulte as informações do blog através do ID do blog na tabela do blog e atribua o blogID e o título de consulta ao objeto do blog;
2. De acordo com a consulta Autorid nas informações do blog, vá à tabela do autor para obter as informações do autor correspondente, obter o objeto do autor e, em seguida, atribui -las ao objeto do blog;
3. Segundo o BlogID, consulte a lista de artigos de postagem correspondente na tabela de postagens e atribua o objeto da lista <Post> ao objeto do blog;
Dessa forma, pelo menos três declarações de consulta são chamadas na camada inferior. Consulte o seguinte código:
/** Obtenha o objeto BlogInfo através do blogID*/ public static bloginfo orgicQueryontest (String blogId) {bigDecimal id = new BigDecimal (blogId); SQLSession Session = sqlSessionFactory.opensssion (); BlogInfo blogInfo = new BlogInfo (); // 1. Consulte o objeto do blog De acordo com o blogID e defina o valor para o blog de blogInfo = (blog) session.selectone ("com.foo.bean.blogmapper.selectByPrimaryKey", id); blogInfo.setBlogId (blog.getBlogId ()); blogInfo.settitle (blog.gettitle ()); // 2. De acordo com o autorid no blog, insira o banco de dados para consultar informações do autor e definir o resultado para o autor do bloginfo objeto autor = (autor) session.selectone ("com.foo.bean.authormapper.selectByPrimaryKey", blog.getauthorid ()); BlogInfo.SetAuthor (autor); // 3. Consulta o objeto de postagens e defina -o como postagens da lista do BlogInfo = session.SelectList ("com.foo.bean.postmapper.selectbyblogid", blog.getBlogId ()); BlogInfo.SetPosts (postagens); // imprima o objeto na forma de um objeto JSON String jsonObject = new JsonObject (BlogInfo); System.out.println (object.toString ()); retornar bloginfo; }Do código acima, podemos ver que é mais problemático obter um objeto BlogInfo. Você deve ligar para a consulta do banco de dados três vezes no total, obter as informações necessárias e, em seguida, montar o objeto BlogInfo.
Consulta de declaração aninhada
Mybatis fornece um mecanismo chamado consulta de declaração aninhada, que pode simplificar bastante as operações acima e adicionar configuração e código da seguinte forma:
<ResultMap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid" /> <resultado column = "title" property = "title" /> <associação propriedade = "autor" column = "blog_author_id" javatype = "com.foo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo" select = "com.foo.bean.authormapper.selectByPrimaryKey"> </association> <collection Property = "Post" column = "blog_id" oftype = "com.foo.bean.post" select = "com.foo.bean.postmapper.selectbyblogid"> </collection> </resultado ResultMap = "BlogInfo" ParameterType = "java.math.bigdecimal"> Selecione B.BLOG_ID, B.TITLE, B.Author_ID como blog_author_id de Louluan.blog B Onde B.BLOG_ID = #{BlogId, JdbcType = Decimal} /** Obtenha o objeto BlogInfo através do blogId*/ public static bloginfo NtestQueryontest (String blogId) {bigDecimal id = new BigDecimal (blogId); SQLSession Session = sqlSessionFactory.opensssion (); BlogInfo blogInfo = new BlogInfo (); BlogInfo = (BlogInfo) session.SelectOne ("com.foo.bean.blogmapper.QueryblogInfobyid", ID); JsonObject Object = New JsonObject (BlogInfo); System.out.println (object.toString ()); retornar bloginfo; }A consulta anterior pode ser totalmente realizada através do código acima. Aqui, precisamos apenas do blogInfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.querybloginfobyid", id); No código, podemos obter um objeto BlogInfo complexo.
O princípio da consulta de declaração aninhada
No código acima, Mybatis executará o seguinte processo:
1. Primeiro, execute a declaração correspondente do querybloginfobyid para obter o conjunto de resultados do resultado da tabela do blog;
2. Retire o próximo registro válido do ResultSet e crie o objeto BlogInfo correspondente com base nas especificações de mapeamento definidas pelo ResultMap.
3. Quando você deseja atribuir o atributo do autor no BlogInfo, você descobre que há uma consulta associada. No momento, o Mybatis executará primeiro a declaração de consulta Select para obter o resultado retornado e definir o resultado ao atributo do autor do BlogInfo;
4. Ao atribuir as postagens do BlogInfo, processos semelhantes também estão presentes.
5. Repita 2 etapas até o ResultSet. próximo () == false;
A seguir, é apresentado um diagrama esquemático do processo de atribuição de construção de objetos do BlogInfo:
Uma função muito boa desse tipo de consulta aninhada associada é que ela pode reutilizar a instrução SELECT e construir objetos complexos através da combinação entre instruções simples de seleção. As duas instruções selecionadas aninhadas acima com.foo.bean.authormapper.SelectByPrimaryKey e com.foo.bean.postmapper.SelectByBlogId podem ser usadas de forma independente.
N+1 problema
Suas desvantagens também são bastante óbvias: o chamado problema n+1. A consulta aninhada associada mostra um conjunto de resultados e, em seguida, a consulta associada é realizada com base em cada registro desse conjunto de resultados.
Agora, suponha que exista apenas uma consulta aninhada (ou seja, existe uma etiqueta de associação dentro do mapa resultante) e o número de entradas retornadas pela consulta é n, a declaração de consulta associada será executada n vezes, mais a consulta retorna o resultado definido para a consulta uma vez e um total de n+1 vezes é necessário para acessar o dados do dados. Se N é relativamente grande, esse consumo de acesso ao banco de dados é muito grande! Portanto, os usuários que usam esse tipo de consulta de declaração aninhados devem considerar cuidadosamente para garantir que o valor N não seja muito grande.
Como exemplo, a instrução SELECT retornará um conjunto de resultados com com.foo.bean.blogmapper.QueryblogInfobyId com 1. Como possui duas consultas de instrução relacionadas, ele precisa acessar o banco de dados 1* (1+1) = 3 vezes no total.
Consulta de resultados aninhados
A consulta de declarações aninhadas pode causar tempos incertos de acesso ao banco de dados, o que pode afetar o desempenho. Mybatis também suporta uma espécie de consulta de resultados aninhados: isto é, para a consulta de situações individuais, muitas para muitas e muitas para uma, o Mybatis pesquisa os resultados do banco de dados de uma só vez, por meio de uma consulta conjunta e, em seguida, converte os resultados baseados em seu relato de um a um para muitos, muitos para o meio-a-o-one, o manipulador e o manifestação e a manutenção e a conflito e a manifestação e a conflito e a manutenção e a configuração do sexo masculino e o manipulamento é o que se refere a muito, muitas vezes, em muitos tempos, por meio de uma consulta e, em seguida, a consulta.
Redefine o mapa do resultado do BlogInfo
<ResultMap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id column = "blog_id" property = "blogid"/> <resultado column = "title" property = "title"/> <Association Property = "Author" Column = "blog_author_id" "javatype =" com.foo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo.Boo " propriedades = "autorid"/> <resultado column = "user_name" propriedade = "nome de usuário"/> <resultado column = "senha" property = "senha"/> <resultado column = "email" property = "email"/> <resultado column = "biography" property = "biography"/> </associação> <coleção = "Posts" column = "blog_Per" "" "".brografia" ". column = "post_id" propriedade = "postId"/> <resultado column = "blog_id" propriedade = "blogid"/> <resultado colun = "create_time" property = "createTime"/> <resultado column = "sujeito" propriedade "súitula"/> <resulte column = "body"/"body/> <resultado" column = "draft" ""/> <>
As instruções SQL correspondentes são as seguintes:
<select id = "QueryallblogInfo" resultMap = "BlogInfo"> Selecione B.BLOG_ID, B.TITLE, B.Author_ID como blog_author_id, A.author_id, A.User_Name, A.Password, A.Email, A.Biografia, P.Post_IdTe, Autor externo esquerdo Autor A on b.author_id = a.author_id de junção externa esquerda Post P no p.blog_id = b.blog_id </leclect>
/** Obtenha todas as informações sobre todos os blogs*/ public static bloginfo nesterSultOntest () {SqlSession Session = sqlSessionFactory.opensssion (); BlogInfo blogInfo = new BlogInfo (); BlogInfo = (BlogInfo) session.SelectOne ("com.foo.bean.blogmapper.queryallbloginfo"); JsonObject Object = New JsonObject (BlogInfo); System.out.println (object.toString ()); retornar bloginfo; } Etapas de execução para consulta de resultados aninhados:
1. Execute operações de junção com base na relação correspondente da tabela para obter o conjunto de resultados;
2. De acordo com as informações do conjunto de resultados e as informações de definição do BlogInfo, montam e atribua o conjunto de resultados retornados na memória para construir o BlogInfo;
3. Retorne a lista de resultados construídos <BlogInfo> Resultado.
Para a consulta de resultados associados, se for um relacionamento muitos para um, é configurado pelo <Association Property = "Author" Column = "blog_author_id" javatype = "com.foo.bean.author">. Mybatis buscará dados da memória através do valor do autor_ID correspondente à propriedade da coluna e o encapsulará em um objeto de autor;
Se for um relacionamento um para muitos, assim como o relacionamento entre o blog e o post, ele é configurado pelo <Coleção property = "posts" column = "blog_post_id" oftype = "com.foo.bean.post">, mybatis usa blog_id para buscar objetos de postagem na memória e encapsulá-los na lista <post>;;
Para consultar os resultados associados, você só precisa consultar o banco de dados uma vez e, em seguida, a integração e montagem dos resultados são todos colocados na memória.
O exposto acima é demonstrar processamento de objetos de mapeamento de um para muitos e muitos para um, consultando todas as informações do blog.
PS: Exemplo de mapeamento de auto-associação:
Classe de entidade
Módulo de classe pública {private int id; chave de string privada; nome de string privado; módulo privado parentmodule; Lista privada <Module> ChildrenModules; URL privado de string; private int sort; show de string privado; String privada del; public int getId () {return id; } public void setId (int id) {this.id = id; } public string getKey () {return Key; } public void setKey (chave de string) {this.key = key; } public string getName () {return name; } public void setName (nome da string) {this.name = name; } módulo público getParentModule () {return parentModule; } public void setParentModule (Module parentModule) {this.parentmodule = parentModule; } public string geturl () {return url; } public void Seturl (String url) {this.url = url; } public int getSort () {return sort; } public void SetSort (int Sort) {this.sort = Sort; } public string getShow () {return show; } public void setShow (String show) {this.show = show; } public string getDel () {return del; } public void setDel (String del) {this.del = del; } Lista pública <Module> getChildrenmodules () {return ChildrenModules; } public void setChildrenModules (List <Module> ChildrenModules) {this.childrenmodules = ChildrenModules; }} Código XML: <Mapper namespace = "com.sagare.caraccess.mapper.moduleMapper"> <resultado column = "module_url"/> <resultado property = "sort" column = "module_sort"/> <result Property = "show" column = "module_show"/> <result Property = "del" column = "module_del"/> <!-consulhe o pai Module-> <associação "=" parentmodule "" column = "<!-consulher o pai Module-> <associação" = "parentmodule" Consulta o submodule-> <coleção de propriedade = "ChildrenModules" column = "module_id" select = "getChildrenmodules"/> </resistmap> <select id = "getModules" parameterType = "string" resultMap = "moduleResultMap"> select * de tb_module " parameterType = "int" resultmap = "moduleResultmap"> selecione * de tb_module onde module_id = #{module_id} </select> <select id = "getChildrenmodues" parameterType = "int" resultMap = "ModuleResultMap"> select * * </mapper>