MyBatis fournit des fonctions de requête d'association avancées, qui peuvent facilement cartographier les ensembles de résultats obtenus par la base de données sur des haricots Java définis. Ce qui suit est un exemple pour montrer comment MyBatis traite des mappages complexes de relation un-à-un communs et plusieurs à un.
Concevez un système de blog simple où un utilisateur peut ouvrir plusieurs blogs, publier des articles dans le blog, autoriser les commentaires et les articles de balises. Le système de blog se compose principalement des tableaux suivants:
Tableau de l'auteur: Tableau d'information de l'auteur, enregistrez les informations de l'auteur, le nom d'utilisateur et le mot de passe, l'adresse e-mail, etc.
Table du blog: Table du blog, un auteur peut ouvrir plusieurs blogs, c'est-à-dire que la relation entre l'auteur et le blog est un à plusieurs.
Tableau de la publication: Tableau d'enregistrement de l'article, enregistrement du temps de publication, titre, texte et autres informations; Il peut y avoir de nombreux articles sous un blog, et la relation entre le blog et le post est un à plusieurs.
Tableau des commentaires: Table des commentaires de l'article, Article d'enregistrement Commentaires, un article peut avoir de nombreux commentaires: La correspondance entre la publication et les commentaires est un à plusieurs.
Tableau de balise: TAGE TABLE, qui représente la classification des balises de l'article. Un article peut avoir plusieurs balises, et une balise peut être appliquée à différents articles, de sorte que la relation entre la balise et le post est une relation plusieurs à plusieurs; (La relation plusieurs à plusieurs entre TAG et POST est reflétée via le tableau post_tag)
Tableau post_tag: enregistre la correspondance entre les articles et les balises.
D'une manière générale, nous créerons un Javabean (ou Pojo) correspondant basé sur la structure de chaque tableau pour terminer le fonctionnement CRUD de base du tableau.
La définition javabéenne ci-dessus d'une seule table ne peut parfois pas répondre aux besoins commerciaux. En affaires, un objet de blog devrait avoir des informations sur son auteur et une liste d'articles, comme le montre la figure ci-dessous:
Si vous souhaitez obtenir une instance d'une telle classe, vous avez besoin d'au moins quelques étapes:
1. Interrogez les informations du blog via l'ID de blog dans la table du blog et attribuez le blog de requête et le titre à l'objet du blog;
2. Selon l'auteur de la requête dans les informations du blog, accédez à la table d'auteur pour obtenir les informations de l'auteur correspondantes, obtenir l'objet de l'auteur, puis les attribuer à l'objet du blog;
3. Selon Blogid, interrogez la liste d'articles de publication correspondante dans la table de publication et attribuez l'objet List <ost> à l'objet blog;
De cette façon, au moins trois instructions de requête sont appelées à la couche inférieure. Veuillez consulter le code suivant:
/ * * Obtenez l'objet bloginfo via Blogid * / public static bloginfo organicQueryonTest (String Blogid) {bigdecimal id = new BigDecimal (blogid); SQLSESSESSE SESSION = SQLSESSESSEFACTORY.OpenSESE (); Bloginfo bloginfo = new bloginfo (); // 1. Interrogez l'objet blog en fonction du blogid et définissez la valeur sur bloginfo blog blog = (blog) session.selectone ("com.foo.bean.blogmapper.selectbyprimaryKey", id); bloginfo.setblogid (blog.getblogid ()); bloginfo.setTitle (blog.getTitle ()); // 2. Selon l'auteur dans le blog, entrez la base de données pour interroger les informations de l'auteur et définissez le résultat sur l'objet bloginfo auteur auteur = (auteur) session.selectone ("com.foo.bean.authormapper.SelectByprimaryKey", blog.getAuthorid ()); bloginfo.setauthor (auteur); // 3. Interrogez l'objet Posts et définissez-le dans BlogInfo List Posts = Session.SelectList ("com.foo.bean.postmapper.selectbyblogid", blog.getblogid ()); bloginfo.setPosts (publications); // Imprime l'objet sous la forme d'une chaîne JSON JSONObject Object = new JSONObject (blogInfo); System.out.println (object.toString ()); retourner bloginfo; }À partir du code ci-dessus, nous pouvons voir qu'il est plus difficile d'obtenir un objet bloginfo. Vous devez appeler la requête de la base de données trois fois au total, obtenir les informations requises, puis assembler l'objet bloginfo.
Requête de déclaration imbriquée
MyBatis fournit un mécanisme appelé Query de déclaration imbriqué, qui peut considérablement simplifier les opérations ci-dessus, et ajouter la configuration et le code comme suit:
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id chronn = "blog_id" propriété = "blogid" /> <result Column = "title" propriété = "title" /> <association propriété = "auteur" column = "blog_author_id" javatype = "com.foo.bean.author" " select = "com.foo.bean.authormapper.SelectByprimaryKey"> </ association> <collection propriété = "poteaux" chronn = "blog_id" ofType = "com.foo.bean.post" select = "com.foo.bean.postmapper.selectbyblogid"> </ collection> </sultMap> <select id = "QueryBlogy resultmap = "bloginfo" paramètreType = "java.math.bigdecimal"> sélectionner b.blog_id, b.title, b.author_id as blog_author_id from louluan.blog b where b.blog_id = # {blogid, jdbcType = Decimal} </ select> / * * Obtenez un objet bloginfo via Blogid * / public static bloginfo NeedSqueryonTest (String Blogid) {BigDecimal ID = new BigDecimal (blogid); SQLSESSESSE SESSION = SQLSESSESSEFACTORY.OpenSESE (); Bloginfo bloginfo = new bloginfo (); bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.querybloginfobyid", id); JsonObject object = new JSONObject (blogInfo); System.out.println (object.toString ()); retourner bloginfo; }La requête précédente peut être pleinement réalisée via le code ci-dessus. Ici, nous avons seulement besoin de bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.querybloginfobyid", id); Dans le code, nous pouvons obtenir un objet BlogInfo complexe.
Le principe de la requête de déclaration imbriquée
Dans le code ci-dessus, MyBatis effectuera le processus suivant:
1. Exécutez d'abord l'instruction correspondante de QueryBloginFobyid pour obtenir l'ensemble de résultats de résultat de la table du blog;
2. Sortez le prochain enregistrement valide du résultat, puis créez l'objet bloginfo correspondant en fonction des spécifications de mappage définies par le résultat.
3. Lorsque vous souhaitez affecter l'attribut de l'auteur dans BlogInfo, vous constatez qu'il existe une requête associée. À l'heure actuelle, MyBatis exécutera d'abord l'instruction de requête sélectionnée pour obtenir le résultat renvoyé et définira le résultat sur l'attribut de l'auteur de BlogInfo;
4. Lors de l'attribution des articles de BlogInfo, des processus similaires sont également présents.
5. Répétez 2 étapes jusqu'à ce que le résultat. suivant () == false;
Ce qui suit est un diagramme schématique du processus d'affectation de construction d'objets Bloginfo:
Une très bonne fonction de ce type de requête imbriquée associée est qu'elle peut réutiliser l'instruction sélectionnée et construire des objets complexes via la combinaison entre les instructions de sélection simples. Les deux déclarations sélectionnées imbriquées ci-dessus com.foo.bean.authormapper.SelectByprimaryKey et com.foo.bean.postmapper.selectbyblogid peuvent être utilisées indépendamment.
N + 1 Problème
Ses inconvénients sont également assez évidents: le soi-disant problème N + 1. La requête imbriquée associée montre un ensemble de résultats, puis la requête associée est effectuée en fonction de chaque enregistrement de cet ensemble de résultats.
Supposons maintenant qu'il n'y ait qu'une seule requête imbriquée (c'est-à-dire qu'il existe une balise d'association dans le résultat), et le nombre d'entrées renvoyés par la requête est n, alors l'instruction de requête associée sera exécutée n fois, plus la requête elle-même renvoie le jeu de résultats sur la requête une fois, et un total de N + 1 fois est requis pour accéder à la base de données. Si N est relativement grand, une telle consommation d'accès à la base de données est très grande! Par conséquent, les utilisateurs qui utilisent ce type de requête de déclaration imbriquée doivent considérer attentivement pour garantir que la valeur n n'est pas très importante.
À titre d'exemple, l'instruction SELECT lui-même renverra un ensemble de résultats avec com.foo.bean.blogmapper.Querybloginfobyid avec 1. Puisqu'il a deux requêtes d'instruction connexes, il doit accéder à la base de données 1 * (1 + 1) = 3 fois au total.
Requête de résultat imbriqué
Interroger les déclarations imbriquées peut entraîner des temps d'accès à la base de données incertains, ce qui peut affecter les performances. MyBatis prend également en charge une sorte de requête de résultats imbriqués: c'est-à-dire pour la requête de situations de la base de données, et de plusieurs à un à un à un, puis de convertit les résultats en fonction des résultats de la données de ses objectifs, et de la configuration de plusieurs à un à un à un à un à des objets.
Redéfinir la carte des résultats de Bloginfo
<resultmap type = "com.foo.bean.bloginfo" id = "bloginfo"> <id chronn = "blog_id" propriété = "blogid" /> <result Column = "title" propriété = "title" /> <association propriété = "Author" column = "blog_author_id" javatype = "com.foE.Bean.Autor"> <id column = "Author_id" Property = "AuthorId" /> <Result Column = "User_name" Property = "Username" /> <Result Column = "Password" Property = "Motway" /> <Result Column = "Email" Property = "Email" /> <Result Column = "Biography" Property = "Biography Id" /> </ Association> <Collection Property = "Posts" Column = "Blog_post_id" ofType = "Com.foo.ban. colonnes = "post_id" propriété = "postid" /> <résultat chronn = "blog_id" propriété = "blogid" /> <result Column = "Create_time" propriété = "CreateTime" /> <result Column = "Subject" Property = "Subject" /> <Result Column = "Body" Property = "Body" /> <Result Column = "Draft" Property = "Draft" /> </ Collection>
Les instructions SQL correspondantes sont les suivantes:
<Select id = "queryAllBloginfo" resultMap = "bloginfo"> select b.blog_id, b.title, b.author_id as blog_author_id, a.authortor_id, a.user_name, a.password, a.email, a.biography, p.post_id, p.blog_id comme blog_post_id, p.create_time, p.blog_id comme blog_post_id, p.create Blog B Left de jointure extérieure A sur b.author_id = a.author_id gauche jointure extérieure Post p sur p.blog_id = b.blog_id </lect>
/ * * Obtenez toutes les informations sur tous les blogs * / public static bloginfo NeedReSultOtest () {SqlSession Session = SQLSessionFactory.OpenSession (); Bloginfo bloginfo = new bloginfo (); bloginfo = (bloginfo) session.selectone ("com.foo.bean.blogmapper.queryallbloginfo"); JsonObject object = new JSONObject (blogInfo); System.out.println (object.toString ()); retourner bloginfo; } Étapes d'exécution pour la requête du résultat imbriqué:
1. Effectuer des opérations de jointure en fonction de la relation correspondante du tableau pour obtenir l'ensemble de résultats;
2. Selon les informations de définition des résultats et les informations de définition de résultat de BlogInfo, assembler et attribuer le résultat renvoyé défini dans la mémoire pour construire BlogInfo;
3. Renvoie la liste de résultats construite <LOGOINFO> Résultat.
Pour la requête de résultat associée, s'il s'agit d'une relation plusieurs à un, il est configuré par la <association propriété = "auteur" colonnel = "blog_author_id" javatype = "com.foo.bean.author">. MyBatis va récupérer les données de la mémoire via la valeur d'auteur_id correspondant à la propriété de colonne et les encapsuler dans un objet d'auteur;
S'il s'agit d'une relation un-à-plusieurs, tout comme la relation entre le blog et le post, il est configuré par la <collection Property = "Posts" Column = "blog_post_id" ofType = "com.foo.bean.post">, Mybatis utilise Blog_ID pour récupérer les objets de publication dans la mémoire et les encapsule dans la liste <ost>;
Pour l'interrogation des résultats associés, il vous suffit de remettre en question la base de données une seule fois, puis l'intégration et l'assemblage des résultats sont tous placés en mémoire.
Ce qui précède consiste à démontrer le traitement d'objets de cartographie un à plusieurs et plusieurs à un en interrogeant toutes les informations du blog.
PS: Exemple de cartographie d'auto-association:
Classe d'entité
Module de classe publique {private int id; clé de chaîne privée; nom de chaîne privé; Module privé ParentModule; Liste privée <Dodule> Children Modules; URL de chaîne privée; INT privé Soi; show de chaîne privée; String privé del; public int getID () {return id; } public void setid (int id) {this.id = id; } public String getKey () {return key; } public void setKey (string key) {this.key = key; } public String getName () {Nom de retour; } public void setName (string name) {this.name = name; } module public 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 tri; } public void setsort (int tri) {this.sort = tri; } 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; } public List <Module> getChildRenModules () {return ChildrenModules; } public void setChildRenDodules (list <module> ChildrenModules) {this.childRenDModules = childrenmodules; }} Code XML: <mapper namespace = "com.sagaware.caraccess.mapper.modulemapper"> <resultMap type = "module" id = "moduleResultMap"> <id propriété = "id" column = "module_id" /> <result Property = "key Column = "module_url" /> <résultat propriété = "srie" chronn = "module_sort" /> <résultat propriété = "show" column = "module_show" /> <result Property = "del" column = "module_del" /> <! - requête le module parent -> <association propriété = "ParentModule" Column = "module_parent_id" Requête le sous-module -> <collection property = "ChildrenModules" Column = "module_id" select = "getChildRenmodules" /> </ resultMap> <select id = "getModules" ParameterType = "String" ResultMap = "moduleResultMap"> Sélectionner * à partir de tb_module où module_id = 2 </ select> paramètreType = "int" resultMap = "moduleResultMap"> Sélectionner * dans TB_Module où module_id = # {module_id} </lect> <select id = "getChildRenModues" ParamEterType = "int" resultMap = "moduleResultMap"> SELECT * </ SELECT où module_parent_id = # {} </capper>