Utilisation avancée de MyBatis

Instruction SQL dynamique

Dynamic SQL est l'une des fonctionnalités puissantes de MyBatis. Si vous avez utilisé JDBC ou d'autres frameworks similaires, vous devez comprendre à quel point il est pénible de raccorder des instructions SQL selon différentes conditions. Par exemple, assurez-vous de ne pas oublier d'ajouter les espaces nécessaires lors du raccordement, et veillez à supprimer la virgule du nom de la dernière colonne de la liste. En utilisant le SQL dynamique, vous pouvez complètement vous débarrasser de cette douleur.

Utiliser du SQL dynamique n'est pas facile, mais MyBatis rend cette fonctionnalité beaucoup plus facile à utiliser grâce au puissant langage SQL dynamique qui peut être utilisé dans n'importe quelle instruction de mappage SQL.

  • si
  • choisir (quand, sinon)
  • trim (où, définir)
  • pour chaque

si

Lorsque du jugement est nécessaire, les conditions sont écrites dans le test

    <select id="selectListIf" parameterType="user" resultMap="BaseResultMap" >
        select
            <include refid="baseSQL"></include>
        from t_user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="userName != null">
                and user_name = #{userName}
            </if>
        </where>
    </select>

choisir

Quand vous devez choisir une condition

    <!-- choose 的使用 -->
    <select id="selectListChoose" parameterType="user" resultMap="BaseResultMap" >
        select
        <include refid="baseSQL"></include>
        from t_user
        <where>
            <choose>
                <when test="id != null">
                    id = #{id}
                </when>
                <when test="userName != null and userName != ''">
                    and user_name like CONCAT(CONCAT('%',#{userName,jdbcType=VARCHAR}),'%')
                </when>
                <otherwise>

                </otherwise>
            </choose>
        </where>
    </select>

garniture

Lorsque vous devez supprimer des symboles tels que où, et et virgules

    <!--
        trim 的使用
        替代where标签的使用
    -->
    <select id="selectListTrim" resultMap="BaseResultMap" 
            parameterType="user">
        select <include refid="baseSQL"></include>
        <trim prefix="where" prefixOverrides="AND |OR ">
            <if test="userName!=null">
                and user_name = #{userName}
            </if>
            <if test="age != 0">
                and age = #{age}
            </if>
        </trim>
    </select>

pour chaque

Quand vous devez parcourir une collection

    <delete id="deleteByList" parameterType="java.util.List">
         delete from t_user 
         where id in
        <foreach collection="list" item="item" open="(" separator="," close=")">
             #{item.id,jdbcType=INTEGER}
        </foreach>
    </delete>

Opération par lots

Il y aura certains scénarios d'opérations par lots dans le projet, tels que l'importation de fichiers dans des données de traitement par lots. Lorsque la quantité de données est très importante, par exemple plus de dizaines de milliers d'éléments, il est définitivement irréaliste d'envoyer du SQL à la base de données pour exécution en boucle dans le code Java, car cela implique de créer des dizaines de milliers de sessions avec la base de données. Même au sein d’une même connexion, la compilation et l’exécution répétées de SQL entraînent une surcharge.

Par exemple, insérer 10 000 éléments dans une boucle (ce qui prend environ 3 secondes) :

public class Test03Batch {
    
    

    public SqlSession session;

    @Before
    public void init() throws IOException {
    
    
        // 1.获取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        // 2.加载解析配置文件并获取SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.根据SqlSessionFactory对象获取SqlSession对象
        session = factory.openSession();
    }

    /**
     * 循环插入10000
     */
    @Test
    public void test1(){
    
    
        long start = System.currentTimeMillis();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int count = 12000;
        for (int i=2000; i< count; i++) {
    
    
            User user = new User();
            user.setUserName("a"+i);
            mapper.insertUser(user);
         }
         session.commit();
         session.close();
         long end = System.currentTimeMillis();
         System.out.println("循环批量插入"+count+"条,耗时:" + (end -start )+"毫秒");
    }
}

MyBatis prend en charge les opérations par lots, y compris les insertions, mises à jour et suppressions par lots. Nous pouvons transmettre directement une liste, un ensemble, une carte ou un tableau, et avec la balise SQL dynamique, MyBatis générera automatiquement une instruction SQL grammaticalement correcte pour nous.

Insertion par lots

Pour l'insertion par lots, ajoutez simplement la valeur insérée après les valeurs.

insert into tbl_emp (emp_id, emp_name, gender,email, d_id) values ( ?,?,?,?,? ),( ?,?,?,?,? ),( ?,?,?,?,? )

Dans le fichier Mapper, nous utilisons la balise foreach pour fusionner les instructions dans la partie valeurs :

    <!-- 批量插入 -->
    <insert id="insertUserList" parameterType="java.util.List" >
        insert into t_user(user_name,real_name)
        values
        <foreach collection="list" item="user" separator=",">
            (#{user.userName},#{user.realName})
        </foreach>

    </insert>

Dans le code Java, un paramètre de type List est directement transmis.

    /**
     * 批量插入
     */
    @Test
    public void test2(){
    
    
        long start = System.currentTimeMillis();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int count = 12000;
        List<User> list = new ArrayList<>();
        for (int i=2000; i< count; i++) {
    
    
            User user = new User();
            user.setUserName("a"+i);
            list.add(user);
        }
        mapper.insertUserList(list);
        session.commit();
        session.close();
        long end = System.currentTimeMillis();
        System.out.println("循环批量插入"+count+"条,耗时:" + (end -start )+"毫秒");
    }

En utilisant la méthode d'insertion par lots, il faut environ 1 seconde pour insérer 10 000 éléments. L'insertion dynamique par lots SQL est beaucoup plus efficace que l'envoi d'une exécution SQL en boucle. Le point le plus critique est de réduire le nombre d’interactions avec la base de données et d’éviter la consommation de temps liée au démarrage et à la fin des transactions.

Mise à jour par lots

La mise à jour par lots utilise le cas où faire correspondre les valeurs des champs liés à l'ID.

update t_user set 
user_name = 
case id 
when ? then ? 
when ? then ? 
when ? then ? end ,
real_name = 
case id
when ? then ? 
when ? then ? 
when ? then ? end 
where id in ( ? , ? , ? )

Par conséquent, la chose la plus critique dans le fichier Mapper est la configuration du cas, du moment et du lieu.

    <update id="updateUserList">
     update t_user set
        user_name =
        <foreach collection="list" item="user" index="index" separator=" " open="case id" close="end">
        when #{user.id} then #{user.userName}
        </foreach>
         ,real_name =
         <foreach collection="list" item="user" index="index" separator=" " open="case id" close="end">
          when #{user.id} then #{user.realName}
         </foreach>
         where id in
         <foreach collection="list" item="item" open="(" separator="," close=")">
          #{item.id,jdbcType=INTEGER}
         </foreach>
     </update>

implémentation du code Java

    /**
     * 批量更新
     */
    @Test
    public void test3(){
    
    
        long start = System.currentTimeMillis();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int count = 12000;
        List<User> list = new ArrayList<>();
        for (int i=2000; i< count; i++) {
    
    
            User user = new User();
            user.setId(i);
            user.setUserName("a"+i);
            list.add(user);
        }
        mapper.updateUserList(list);
        session.commit();
        session.close();
        long end = System.currentTimeMillis();
        System.out.println("批量更新"+count+"条,耗时:" + (end -start )+"毫秒");
    }

suppression par lots

La suppression par lots est similaire.

    <delete id="deleteByList" parameterType="java.util.List">
         delete from t_user where id in
        <foreach collection="list" item="item" open="(" separator="," close=")">
            #{item.id,jdbcType=INTEGER}
        </foreach>
    </delete>

BatchExecutor

Le fonctionnement par lots des balises dynamiques de MyBatis présente également certains inconvénients : par exemple, lorsque la quantité de données est particulièrement importante, l'instruction SQL épissée est trop volumineuse.

Le serveur MySQL a une limite de taille pour les paquets de données reçus. Le max_allowed_packet par défaut est de 4 Mo. Vous devez modifier la configuration par défaut ou contrôler manuellement le nombre pour résoudre ce problème.

Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (7188967 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.

Dans le fichier de configuration globale, vous pouvez configurer le type d'exécuteur par défaut (la valeur par défaut est SIMPLE). Parmi eux se trouve BatchExecutor.

<setting name="defaultExecutorType" value="BATCH" />

Vous pouvez également spécifier le type d'exécuteur lors de la création d'une session

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);

Exécuteur

image.png

  1. SimpleExecutor : chaque fois qu'une mise à jour ou une sélection est exécutée, un objet Statement est ouvert et l'objet Statement est fermé immédiatement après utilisation.
  2. ReuseExecutor : exécutez update ou select, utilisez sql comme clé pour trouver l'objet Statement, utilisez-le s'il existe et créez-le s'il n'existe pas. Après utilisation, l'objet Statement n'est pas fermé, mais placé dans la carte pour le prochain utiliser. En bref, il s’agit de réutiliser des objets Statement.
  3. BatchExecutor : exécute la mise à jour (pas de sélection, le traitement par lots JDBC ne prend pas en charge la sélection), ajoute tout le SQL au lot (addBatch()), attend l'exécution unifiée (executeBatch()), il met en cache plusieurs objets Statement, chacun après les objets Statement sont complétés par addBatch(), ils attendent que le traitement par lotsexecuteBatch() soit exécuté un par un. Identique au traitement par lots JDBC. executeUpdate() est une instruction qui accède à la base de données une fois, et executeBatch() est un lot d'instructions qui accèdent à la base de données une fois (le nombre spécifique de SQL envoyés dans un lot est lié au max_allowed_packet du serveur). La couche inférieure de BatchExecutor est une encapsulation de JDBC ps.addBatch() et ps.executeBatch().

Requête associée

Requêtes imbriquées

Lors de l'interrogation de données d'entreprise, nous rencontrons souvent des requêtes associées. Par exemple, l'interrogation des employés sera associée aux départements (un à un), l'interrogation des notes des étudiants sera associée aux cours (un à un) et l'interrogation des commandes sera associés aux produits (un à un). plus) et ainsi de suite.

Requête imbriquée 1 à 1, 1 utilisateur correspond à un service

 
    <resultMap id="nestedMap1" type="user">
        <id property="id" column="id" jdbcType="INTEGER"/>
        <result property="userName" column="user_name" jdbcType="VARCHAR" />
        <result property="realName" column="real_name" jdbcType="VARCHAR" />
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="dId" column="d_id" jdbcType="INTEGER"/>
        <association property="dept" javaType="dept">
            <id column="did" property="dId"/>
            <result column="d_name" property="dName"/>
            <result column="d_desc" property="dDesc"/>
        </association>
    </resultMap>

    <select id="queryUserNested" resultMap="nestedMap1">
        SELECT
            t1.`id`
            ,t1.`user_name`
            ,t1.`real_name`
            ,t1.`password`
            ,t1.`age`
            ,t2.`did`
            ,t2.`d_name`
            ,t2.`d_desc`
        FROM t_user t1
        LEFT JOIN
            t_department t2
            ON t1.`d_id` = t2.`did`
    </select>

Requête imbriquée 1 à plusieurs, 1 département a plusieurs utilisateurs

<!-- -->
    <resultMap id="nestedMap2" type="dept">
        <id column="did" property="dId"/>
        <result column="d_name" property="dName"/>
        <result column="d_desc" property="dDesc"/>
        <collection property="users" ofType="user">
            <id property="id" column="id" jdbcType="INTEGER"/>
            <result property="userName" column="user_name" jdbcType="VARCHAR" />
            <result property="realName" column="real_name" jdbcType="VARCHAR" />
            <result property="password" column="password" jdbcType="VARCHAR"/>
            <result property="age" column="age" jdbcType="INTEGER"/>
            <result property="dId" column="d_id" jdbcType="INTEGER"/>
        </collection>
    </resultMap>
    <select id="queryDeptNested" resultMap="nestedMap2">
        SELECT
            t1.`id`
            ,t1.`user_name`
            ,t1.`real_name`
            ,t1.`password`
            ,t1.`age`
            ,t2.`did`
            ,t2.`d_name`
            ,t2.`d_desc`
        FROM t_user t1
        RIGHT JOIN
            t_department t2
            ON t1.`d_id` = t2.`did`
    </select>

Chargement paresseux

Ce problème peut être résolu en activant le commutateur de chargement différé dans MyBatis.

Vous pouvez le configurer dans la balise settings :

<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!--当开启时,任何方法的调用都会加载该对象的所有属性。默认false,可通过select标签的 fetchType来覆盖-->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- MyBatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
<setting name="proxyFactory" value="CGLIB" />

lazyLoadingEnabled détermine s'il faut charger paresseusement (false par défaut).

agressifLazyLoading détermine si toutes les méthodes de l'objet déclencheront des requêtes.

Configuration de chargement paresseux 1 à 1

    <!-- 延迟加载 1对1 -->
    <resultMap id="nestedMap1Lazy" type="user">
        <id property="id" column="id" jdbcType="INTEGER"/>
        <result property="userName" column="user_name" jdbcType="VARCHAR" />
        <result property="realName" column="real_name" jdbcType="VARCHAR" />
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="dId" column="d_id" jdbcType="INTEGER"/>
        <association property="dept" javaType="dept" column="d_id" select="queryDeptByUserIdLazy">

        </association>
    </resultMap>
    <resultMap id="baseDept" type="dept">
        <id column="did" property="dId"/>
        <result column="d_name" property="dName"/>
        <result column="d_desc" property="dDesc"/>
    </resultMap>
    <select id="queryUserNestedLazy" resultMap="nestedMap1Lazy">
        SELECT
            t1.`id`
            ,t1.`user_name`
            ,t1.`real_name`
            ,t1.`password`
            ,t1.`age`
            ,t1.d_id
        FROM t_user t1
    </select>
    <select id="queryDeptByUserIdLazy" parameterType="int" resultMap="baseDept">
        select * from t_department where did = #{did}
    </select>

Lorsque le commutateur de chargement différé est activé, la deuxième requête ne sera pas lancée tant que user.getDept() ne sera pas appelé ;

    /**
     * 1对1  关联查询 延迟加载
     * @throws Exception
     */
    @Test
    public void test03() throws Exception{
    
    
        init();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.queryUserNestedLazy();
        for (User user : users) {
    
    
      
            System.out.println(user.getUserName() + "---->"+user.getDept());
        }
    }

opération de radiomessagerie

Pagination logique

Il existe un objet de pagination logique RowBounds dans MyBatis, qui a principalement deux attributs, offset et limit (à partir de quel élément, combien d'éléments sont interrogés). On peut ajouter ce paramètre à la méthode de l'interface Mapper sans modifier l'instruction SQL dans le XML.

défini dans l'interface

    public List<User> queryUserList(RowBounds rowBounds);

Classe d'essai

    @Test
    public void test01() throws Exception{
    
    
        init();
        UserMapper mapper = session.getMapper(UserMapper.class);
        // 设置分页的数据
        RowBounds rowBounds = new RowBounds(1,3);
        List<User> users = mapper.queryUserList(rowBounds);
        for (User user : users) {
    
    
            System.out.println(user);
        }
    }

Le principe de fonctionnement de RowBounds est en fait le traitement de ResultSet. Il supprimera les données de décalage précédentes, puis prendra les données limites des données restantes.

// DefaultResultSetHandler.java
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    
    
   DefaultResultContext<Object> resultContext = new DefaultResultContext();
   ResultSet resultSet = rsw.getResultSet();
   this.skipRows(resultSet, rowBounds);
   while(this.shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    
    
       ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(resultSet, resultMap, (String)null);
       Object rowValue = this.getRowValue(rsw, discriminatedResultMap, (String)null);
       this.storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
  }
}

Évidemment, si la quantité de données est importante, l'efficacité de cette méthode de tournage de page sera très faible (pas différente de l'interrogation en mémoire puis de l'utilisation de subList(start, end)). Nous devons donc utiliser le tournage physique des pages.

radiomessagerie physique

Le changement de page physique est un véritable changement de page : il tourne les pages grâce à des instructions prises en charge par la base de données.

La première méthode simple consiste à transmettre des paramètres (ou à envelopper un objet de page) et à tourner les pages dans l'instruction SQL.

<select id="selectUserPage" parameterType="map" resultMap="BaseResultMap">
  select * from t_user limit #{curIndex} , #{pageSize}
</select>

Il y a deux problèmes avec cette méthode : le premier problème est que nous devons calculer les numéros de séquence de début et de fin dans le code métier Java ; le deuxième problème est : chaque instruction qui doit être paginée doit écrire une instruction de limite, ce qui entraînera le mappeur Mapper vers Il contient beaucoup de code redondant.

Nous avons besoin d'une méthode universelle qui ne nécessite de modifier aucune instruction SQL dans la configuration. Il suffit de transmettre la page actuelle et le nombre d'entrées par page, et les numéros de série de début et de fin seront automatiquement calculés.

Notre approche la plus courante consiste à utiliser des plug-ins de rotation de pages, tels que PageHelper.

// pageSize每一页几条
PageHelper.startPage(pn, 10);
List<Employee> emps = employeeService.getAll();
// navigatePages 导航页码数
PageInfo page = new PageInfo(emps, 10);
return Msg.success().add("pageInfo", page);

PageHelper est implémenté via l'intercepteur de MyBatis. En termes simples, il réécrira notre instruction SQL en fonction des paramètres de PageHelper. Par exemple, MySQL générera une instruction limit, Oracle générera une instruction rownum et SQL Server générera une instruction top.

Générateur MyBatis

Lorsque vous utilisez MyBaits dans un projet, vous devez créer une classe d'entité, un mappeur Mapper et une interface Mapper pour une table qui doit être exploitée. Il contient de nombreux champs et configurations de méthodes. Cette partie du travail est très fastidieuse. La plupart du temps, nos opérations de base sur la table sont les mêmes, comme l'interrogation basée sur la clé primaire, l'interrogation basée sur Map, l'insertion unique, l'insertion par lots, la suppression basée sur la clé primaire, etc. Quand on a beaucoup de tables, cela demande beaucoup de travail répété.

Existe-t-il donc un moyen de générer automatiquement des classes d'entités, des mappeurs Mapper et des interfaces Mapper basés sur nos tables, qui contiennent les méthodes de base et le SQL que nous devons utiliser ?

MyBatis fournit également un générateur de code appelé MyBatis Generator, appelé MBG (il s'agit d'un plug-in pour MyBatis). Il nous suffit de modifier un fichier de configuration et d'utiliser les commandes du package jar ou le code Java correspondant pour nous aider à générer des classes d'entités, des mappeurs et des fichiers d'interface.

Il y a un commutateur Exemple dans le fichier de configuration MBG. Cet élément est utilisé pour construire des conditions de filtrage complexes. En d'autres termes, il génère des conditions Where basées sur notre code.

Principe : La classe d'entité contient deux critères avec une relation d'héritage, et les méthodes générées automatiquement sont utilisées pour construire des conditions de requête. Transmettez cette classe d'entité contenant des critères en tant que paramètre au paramètre de requête, et elle sera convertie en conditions SQL lors de l'analyse du mappeur Mapper.

Ajouter un fichier de configuration

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- 数据库的驱动包路径 -->
    <classPathEntry location="C:\Users\mysql-connector-java-8.0.11.jar" />

    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 去掉生成文件中的注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 数据库链接URL、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/db?characterEncoding=utf-8&serverTimezone=UTC"
                        userId="root"
                        password="123456">
            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- 生成模型的包名和位置 -->
        <javaModelGenerator targetPackage="com.domain" targetProject="./src/main/java">
            <!-- 是否在当前路径下新加一层schema -->
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- 生成的映射文件包名和位置 -->
        <sqlMapGenerator targetPackage="com.mapper"  targetProject="./src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.mapper"  targetProject="./src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <table  tableName="t_user" domainObjectName="User"   />


    </context>
</generatorConfiguration>

ajouter un plugin

Ajoutez le plug-in correspondant dans pom.xml

    <build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <!-- 指定配置文件的位置 -->
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                </configuration>
            </plugin>
        </plugins>
    </build>

générer

Le plug-in d'exécution du projet maven nous aide à générer rapidement les fichiers pertinents correspondant à la structure de table requise.

Mappeur universel

Lorsque les champs de notre table changent, nous devons modifier les champs et les méthodes définis dans la classe d'entité et le fichier Mapper. S'il s'agit d'une maintenance incrémentielle, modifiez les fichiers un par un. S'il s'agit d'un remplacement complet, nous devons également comparer les fichiers générés avec MBG. Chaque fois qu'un champ change, il doit être modifié une fois, ce qui est très difficile à maintenir.

première méthode

Parce que MyBatis' Mapper prend en charge l'héritage. Par conséquent, Mapper.xml et l’interface Mapper peuvent être divisés en deux fichiers. L'un est généré par MBG, et cette partie est corrigée. Créez ensuite une classe DAO qui hérite de l'interface générée et les parties modifiées sont conservées dans DAO.

public interface UserMapperExt extends UserMapper {
    
    
    public List<User> selectUserByName(String userName);
}

Fichier de mappage correspondant

<?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="com.mapper.UserMapperExt" >
  <resultMap id="BaseResultMapExt" type="com.domain.User" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="user_name" property="userName" jdbcType="VARCHAR" />
    <result column="real_name" property="realName" jdbcType="VARCHAR" />
    <result column="password" property="password" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
    <result column="d_id" property="dId" jdbcType="INTEGER" />
    <result column="i_id" property="iId" jdbcType="INTEGER" />
  </resultMap>
  
  <select id="selectUserByName" resultMap="BaseResultMapExt" >
    select * from t_user where user_name = #{userName}
  </select>
</mapper>

Dans le fichier de configuration globale, nous devons également analyser

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
        <mapper resource="mapper/UserMapperExt.xml"/>
    </mappers>

Ainsi, à l’avenir, il vous suffira de modifier le fichier Ext. L’un des inconvénients de cette procédure est que le nombre de fichiers augmentera.

Méthode 2

Étant donné que les méthodes de base générées pour chaque table sont les mêmes, c'est-à-dire que la partie méthode publique du code est la même, cette partie peut-elle être fusionnée en un seul fichier et lui permettre de prendre en charge les génériques ?

Écrivez une interface générale qui prend en charge les génériques, tels que GPBaseMapper, et transmettez la classe d'entité en tant que paramètre. Cette interface définit un grand nombre de méthodes de base pour l'ajout, la suppression, la modification et l'interrogation, et ces méthodes prennent toutes en charge les génériques.

Une interface Mapper personnalisée hérite de cette interface générale, telle que BlogMapper étend GPBaseMapper et obtient automatiquement les méthodes de fonctionnement pour les classes d'entités. Si nous rencontrons des méthodes qui n'existent pas, nous pouvons toujours les écrire dans notre propre Mapper.

La solution à laquelle on peut penser a déjà été élaborée par quelqu'un. Cette chose s'appelle Universal Mapper .

Objectif : Résout principalement le problème de l'ajout, de la suppression, de la modification et de l'interrogation d'une seule table. Il ne convient pas aux scénarios de requête liés à plusieurs tables.

En plus du problème des modifications des fichiers de configuration, Universal Mapper peut également résoudre :

  1. Un grand nombre de définitions de méthodes répétées dans chaque interface Mapper ;
  2. Masquer les différences dans les bases de données ;
  3. Fournir des méthodes pour les opérations par lots ;
  4. Implémentez la pagination.

Utilisation : lorsqu'il est utilisé au printemps, introduisez le package jar, remplacez sqlSessionFactory et configurez dans applicationContext.xml.

<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
   <property name="basePackage" value="com.crud.dao"/>
</bean>

MyBatis-Plus

MyBatis-Plus est un outil amélioré pour MyBatis natif. Il peut utiliser les fonctions uniques de plus sur la base de l'utilisation de toutes les fonctions de MyBatis natif.

Fonctions principales de MyBatis-Plus :

Universal CRUD : Après avoir défini l'interface Mapper, il vous suffit d'hériter de l'interface BaseMapper pour obtenir les fonctions universelles d'ajout, de suppression, de modification et de requête sans écrire de méthodes d'interface ni de fichiers de configuration.

Constructeur conditionnel : grâce à EntityWrapper (classe wrapper d'entité), il peut être utilisé pour fusionner des instructions SQL et prend en charge le SQL complexe tel que le tri et le regroupement de requêtes.

Générateur de code : prend en charge une série de configurations de politiques et de configurations globales, ce qui est plus utilisable que la génération de code MyBatis.

おすすめ

転載: blog.csdn.net/qq_28314431/article/details/133087651