Maison  >  Questions et réponses  >  le corps du texte

java - Problème de pagination lié à plusieurs tables de la base de données Mybatis

Par exemple :
Il existe deux classes d'entités Utilisateur et Adresse

public class User {
    private int id;
    private String username; // 用户名
    private List<Address> addresses;
    // getter setter...
}

public class Address {
    private int id;
    private String detail; // 详细地址
    private User user;    //所属用户
    // getter setter...
}

Base de données :

create table t_user(
    id int(10) primary key auto_increment,
    username varchar(50)
);


create table t_address(
    id int(10) primary key auto_increment,
    detail varchar(255),
    user_id int(10),
    CONSTRAINT FOREIGN KEY (user_id) REFERENCES t_user(id)
);

Configuration de la cartographie mybatis :


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mkh.shop.model.User">
    <resultMap type="User" id="userMap" autoMapping="true">
        <id property="id" column="u_id"/>
        <collection property="address" ofType="Address">
            <id property="id" column="a_id"/>
            <result property="detail" column="detail"/>
        </collection>
    </resultMap>

    <select id="find" resultType="User" parameterType="map">
        select  *,
                ta.id as 'a_id',
                tu.id as 'u_id' 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
        <if test="sort != null">
            order by ${sort} 
            <choose>
                <when test="order != null">${order}</when>
                <otherwise>asc</otherwise>
            </choose> 
        </if>
        limit #{pageOffset},#{pageSize}
    </select>
    
    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    </select>    
</mapper> 

La relation entre les utilisateurs et les adresses est la suivante : un utilisateur a plusieurs adresses, une adresse ne peut appartenir qu'à un seul utilisateur, une à plusieurs
Supposons que la demande actuelle soit d'interroger les utilisateurs dans des pages, de les afficher dans un tableau et de tous les afficher. adresses de chaque utilisateur Sortez
Ensuite, le problème survient
Il n'y a aucun problème avec les données de pagination renvoyées selon la requête ci-dessus, mais le nombre total d'enregistrements de pagination est erroné.
Par exemple, les données trouvées (données de la base de données, pas affichage de la page) sont les suivantes :

u_id nom d'utilisateur a_id détail
1 utilisateur1 1 District de Haidian, Pékin
1 utilisateur1 2 District de Chaoyang, Pékin
2 utilisateur2 3 Ville de Tianjin

Parce que mon exigence est d'afficher les utilisateurs dans des pages, un utilisateur est donc une donnée affichée sur la page, qui ressemble à ceci. En théorie, il s'agit de deux données,

.
ID utilisateur Nom d'utilisateur Adresse
1 utilisateur1 1. District de Haidian, Pékin 2. District de Chaoyang, Pékin
2 utilisateur2 1. Ville de Tianjin
1 page au total, 2 éléments de données au total, 10 éléments affichés sur chaque page

Cependant, d'après la configuration find_count de mybatis, on constate qu'il y a 3 éléments. Comment résoudre ce problème ?
Lors de l'interrogation de count(*), toutes les tables associées à la jointure gauche doivent-elles être supprimées ? Cela rendra-t-il les données renvoyées inexactes ?


Explication supplémentaire : j'ai l'impression que tout le monde a mal compris ce que je voulais dire. En fait, mon problème concerne principalement SQL, pas mybatis, car une fois les données que j'ai interrogées ont été mappées, il n'y a eu aucun problème, c'était juste une pagination. il y a un problème avec le nombre total d'enregistrements, entraînant une pagination incorrecte

黄舟黄舟2660 Il y a quelques jours1464

répondre à tous(6)je répondrai

  • 漂亮男人

    漂亮男人2017-06-10 09:51:39

    Je viens d'écrire un exemple et de le tester

    `

    Deux classes d'entités
    classe publique Utilisateur {

    
    private int id;
    private String username; // 用户名
    private List<Address> addresses;
    

    Adresse de classe publique {

    private int id;
    private String detail; // 详细地址
    private int user_id; // 所属用户
    

    Fichier de cartographie
    <resultMap type="com.atguigu.mybatis.entity.User" id="userMap" autoMapping="true">

        <result property="id" column="u_id"/>
        <collection property="addresses" ofType="com.atguigu.mybatis.entity.Address" autoMapping="true">
            <result property="id" column="a_id"/>
            <result property="user_id" column="u_id"/>
        </collection>
    </resultMap>
    
    <select id="select_all_user_address"  resultMap="userMap" >

    <!-- sélectionnez tu.,ta., -->
    <!-- ta.id comme 'a_id', -->
    <!-- tu.id comme 'u_id' -->
    <!-- de t_user tu , -->
    <!-- t_address ta où ta.user_id=tu.id -->

            
             select   tu.*,ta.*,
                ta.id as 'a_id',
                tu.id as 'u_id' 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
    </select>
    

    Résultats des tests

    La taille de la liste encapsulée<Utilisateur> ne pose aucun problème

    répondre
    0
  • ringa_lee

    ringa_lee2017-06-10 09:51:39

    Regroupez les mots clés par et vérifiez vous-même l'opération spécifique

    répondre
    0
  • 欧阳克

    欧阳克2017-06-10 09:51:39

    SELECT 
        *, ta.id AS 'a_id', tu.id AS 'u_id'
    FROM
        t_user tu
            LEFT JOIN
        t_address ta ON ta.user_id = tu.id;

    Vous espérez vouloir deux éléments, mais votre SQL trouve trois éléments, donc une erreur s'affiche
    Vous devez diviser la logique :
    Vous devez d'abord trouver l'utilisateur que vous souhaitez

    .
    <select id="find" resultType="User" parameterType="map">
            select  *
            from t_user tu 
            <where> 
                <if test="name != null">
                    (username like #{name})
                </if>
            </where>
            <if test="sort != null">
                order by ${sort} 
                <choose>
                    <when test="order != null">${order}</when>
                    <otherwise>asc</otherwise>
                </choose> 
            </if>
            limit #{pageOffset},#{pageSize}
        </select>

    Puis dans

        <resultMap type="User" id="userMap" autoMapping="true">
            <id property="id" column="u_id"/>
            <collection " property="addresses" javaType= "ArrayList" column="u_id"
     ofType="Address" select= "??" />
        </resultMap>

    ??C'est une méthode pour vérifier List<Address> en utilisant l'ID utilisateur par vous-même

    répondre
    0
  • 欧阳克

    欧阳克2017-06-10 09:51:39

    Dans ce cas, la pagination ne peut pas être effectuée de cette manière. Vous devez paginer les données de la table principale.

    À l'origine, 100 éléments de données ont été interrogés, mais comme un vers plusieurs pliera et dédupliquera un grand nombre de données, les résultats réels étaient inférieurs à 100 éléments.

    Dans ce cas, une requête imbriquée peut être utilisée pour résoudre le problème, qui nécessite N+1 exécutions et peut être chargée paresseusement.

    Ou regardez ici : https://my.oschina.net/flags/...

    Pour le contenu MyBatis, veuillez visiter : http://mybatis.tk

    répondre
    0
  • 扔个三星炸死你

    扔个三星炸死你2017-06-10 09:51:39

    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu 
            left join t_address ta on ta.user_id=tu.id 
        <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    </select> 

    Modifier :

    <select id="find_count" resultType="int" parameterType="map">
        select count(*) 
        from t_user tu
       <where> 
            <if test="name != null">
                (username like #{name})
            </if>
        </where>
    
        group by username
    </select> 
    

    répondre
    0
  • 曾经蜡笔没有小新

    曾经蜡笔没有小新2017-06-10 09:51:39

    Il n'y aura aucun problème si vous utilisez une sous-requête

    select count(*) from (
       // query 在这里即使关联100张表, 也不可能存在问题
    )

    L'auteur peut jeter un œil à Mybatis-PageHelper implémentation de la conversion SQL

    Il est recommandé à l'auteur d'utiliser directement Mybatis-PageHelper pour implémenter la pagination

    répondre
    0
  • Annulerrépondre