Uso avanzado de MyBatis

Declaración SQL dinámica

SQL dinámico es una de las poderosas características de MyBatis. Si ha utilizado JDBC u otros marcos similares, debe comprender lo doloroso que es unir declaraciones SQL de acuerdo con diferentes condiciones. Por ejemplo, asegúrese de no olvidar agregar los espacios necesarios al unir y tenga cuidado de eliminar la coma del último nombre de columna en la lista. Con SQL dinámico, puede deshacerse completamente de este dolor.

Trabajar con SQL dinámico no es fácil, pero MyBatis hace que esta característica sea mucho más fácil de usar con el poderoso lenguaje SQL dinámico que se puede usar en cualquier declaración asignada de SQL.

  • si
  • elegir (cuando, de lo contrario)
  • recortar (dónde, establecer)
  • para cada

si

Cuando se necesita juicio, las condiciones están escritas en la prueba.

    <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>

elegir

Cuando necesitas elegir una condición.

    <!-- 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>

recortar

Cuando necesita eliminar símbolos como dónde, y y comas

    <!--
        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>

para cada

Cuando necesitas recorrer una colección

    <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>

Operaciones por lotes

Habrá algunos escenarios de operación por lotes en el proyecto, como la importación de archivos para procesar datos por lotes. Cuando la cantidad de datos es muy grande, como más de decenas de miles de elementos, definitivamente no es realista enviar SQL a la base de datos para ejecución en un bucle en el código Java, porque esto significa crear decenas de miles de sesiones con la base de datos. Incluso dentro de la misma conexión, existe la sobrecarga de compilar y ejecutar SQL repetidamente.

Por ejemplo, insertar 10.000 elementos en un bucle (tarda unos 3 segundos):

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 admite operaciones por lotes, incluidas inserciones, actualizaciones y eliminaciones por lotes. Podemos pasar directamente una Lista, Conjunto, Mapa o matriz, y con la etiqueta SQL dinámica, MyBatis generará automáticamente una declaración SQL gramaticalmente correcta para nosotros.

Inserto de lote

Para la inserción por lotes, simplemente agregue el valor insertado después de los valores.

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

En el archivo Mapper, usamos la etiqueta foreach para unir las declaraciones en la parte de valores:

    <!-- 批量插入 -->
    <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>

En el código Java, se pasa directamente un parámetro de tipo Lista.

    /**
     * 批量插入
     */
    @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 )+"毫秒");
    }

Con el método de inserción por lotes, se tarda aproximadamente 1 segundo en insertar 10.000 elementos. La inserción por lotes de SQL dinámico es mucho más eficiente que enviar la ejecución de SQL en un bucle. El punto más crítico es reducir la cantidad de interacciones con la base de datos y evitar el consumo de tiempo al iniciar y finalizar transacciones.

Actualización por lotes

La actualización por lotes utiliza el caso cuando coincide con los valores de los campos relacionados con el 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 ( ? , ? , ? )

Por lo tanto, lo más crítico en el archivo Mapper es la configuración del caso, cuándo y dónde.

    <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>

implementación de código 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 )+"毫秒");
    }

eliminación por lotes

La eliminación por lotes es similar.

    <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>

Ejecutor por lotes

La operación por lotes de etiquetas dinámicas de MyBatis también tiene ciertas deficiencias: por ejemplo, cuando la cantidad de datos es particularmente grande, la declaración SQL empalmada es demasiado grande.

El servidor MySQL tiene un límite de tamaño para los paquetes de datos recibidos. El max_allowed_packet predeterminado es 4 M. Es necesario modificar la configuración predeterminada o controlar manualmente el número para resolver este problema.

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.

En el archivo de configuración global, puede configurar el tipo de Ejecutor predeterminado (el valor predeterminado es SIMPLE). Entre ellos se encuentra BatchExecutor.

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

También puede especificar el tipo de ejecutor al crear una sesión.

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

Ejecutor

imagen.png

  1. SimpleExecutor: cada vez que se ejecuta una actualización o selección, se abre un objeto Declaración y el objeto Declaración se cierra inmediatamente después de su uso.
  2. ReuseExecutor: ejecute la actualización o seleccione, use sql como clave para encontrar el objeto Declaración, úselo si existe y créelo si no existe. Después de su uso, el objeto Declaración no se cierra, sino que se coloca en el Mapa para el siguiente usar. En resumen, se trata de reutilizar objetos Statement.
  3. BatchExecutor: ejecuta la actualización (sin selección, el procesamiento por lotes JDBC no admite la selección), agrega todo sql al lote (addBatch ()), espera la ejecución unificada (executeBatch ()), almacena en caché varios objetos de declaración, cada uno después de los objetos de declaración se completan con addBatch (), esperan a que el procesamiento por lotes de ejecutarBatch () se ejecute uno por uno. Igual que el procesamiento por lotes JDBC. ejecutarUpdate() es una declaración que accede a la base de datos una vez, y ejecutarBatch() es un lote de declaraciones que acceden a la base de datos una vez (el número específico de SQL enviados en un lote está relacionado con el max_allowed_packet del servidor). La capa inferior de BatchExecutor es una encapsulación de JDBC ps.addBatch() y ps.executeBatch().

Consulta relacionada

consultas anidadas

Al consultar datos comerciales, a menudo encontramos consultas relacionadas: por ejemplo, consultar a los empleados se asociará con los departamentos (uno a uno), consultar las calificaciones de los estudiantes se asociará con los cursos (uno a uno) y consultar los pedidos. asociados con productos (uno a uno). más) y así sucesivamente.

Consulta anidada 1 a 1, 1 usuario corresponde a un departamento

 
    <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>

Consulta anidada 1 a muchos, 1 departamento tiene varios usuarios

<!-- -->
    <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>

Carga lenta

Este problema se puede resolver activando el interruptor de carga retrasada en MyBatis.

Puedes configurarlo en la pestaña de configuración:

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

lazyLoadingEnabled determina si se realiza una carga diferida (falso predeterminado).

agresivoLazyLoading determina si todos los métodos del objeto activarán consultas.

Configuración de carga diferida 1 a 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>

Cuando el interruptor de carga retrasada está activado, la segunda consulta no se iniciará hasta que se llame a user.getDept();

    /**
     * 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());
        }
    }

operación de paginación

paginación lógica

Hay un objeto de paginación lógico RowBounds en MyBatis, que tiene principalmente dos atributos, desplazamiento y límite (comience desde qué elemento y cuántos elementos se consultan). Podemos agregar este parámetro al método de la interfaz Mapper sin modificar la declaración SQL en el xml.

definido en la interfaz

    public List<User> queryUserList(RowBounds rowBounds);

clase de prueba

    @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);
        }
    }

El principio de funcionamiento de RowBounds es en realidad el procesamiento de ResultSet. Descartará los datos de compensación anteriores y luego tomará los datos límite de los datos 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);
  }
}

Obviamente, si la cantidad de datos es grande, la eficiencia de este método de paso de página será muy baja (no es diferente de consultar en la memoria y luego usar subList (inicio, fin)). Por lo tanto, necesitamos utilizar el paso de página físico.

paginación física

El paso de página físico es un paso de página real: pasa páginas a través de declaraciones respaldadas por la base de datos.

La primera forma sencilla es pasar parámetros (o envolver un objeto de página) y pasar páginas en la declaración SQL.

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

Hay dos problemas con este método: el primer problema es que necesitamos calcular los números de secuencia inicial y final en el código comercial Java; el segundo problema es: cada declaración que necesita ser paginada debe escribir una declaración de límite, lo que causará el mapeador Mapper tiene una gran cantidad de código redundante.

Necesitamos un método universal que no requiera modificar ninguna declaración SQL en la configuración, solo necesitamos pasar la página actual y el número de entradas por página, y los números de serie inicial y final se calcularán automáticamente.

Nuestro enfoque más común es utilizar complementos para pasar páginas, como 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 se implementa a través del interceptor de MyBatis y, en pocas palabras, reescribirá nuestra declaración SQL de acuerdo con los parámetros de PageHelper. Por ejemplo, MySQL generará una declaración de límite, Oracle generará una declaración de rownum y SQL Server generará una declaración superior.

Generador MyBatis

Cuando se utiliza MyBaits en un proyecto, es necesario crear una clase de entidad, un mapeador Mapper y una interfaz Mapper para una tabla que necesita ser operada. Hay muchos campos y configuraciones de métodos en ella. Esta parte del trabajo es muy tediosa. La mayoría de las veces, nuestras operaciones básicas en la tabla son las mismas, como consultas basadas en la clave principal, consultas basadas en el mapa, inserción única, inserción por lotes, eliminación según la clave principal, etc. Cuando tenemos muchas mesas, significa mucho trabajo repetido.

Entonces, ¿hay alguna manera de generar automáticamente clases de entidad, mapeadores Mapper e interfaces Mapper basadas en nuestras tablas, que contienen los métodos básicos y SQL que necesitamos usar?

MyBatis también proporciona un generador de código llamado MyBatis Generator, conocido como MBG (es un complemento para MyBatis). Solo necesitamos modificar un archivo de configuración y usar los comandos del paquete jar relevantes o el código Java para ayudarnos a generar clases de entidad, mapeadores y archivos de interfaz.

Hay un modificador de ejemplo en el archivo de configuración de MBG. Este elemento se utiliza para construir condiciones de filtrado complejas. En otras palabras, genera condiciones Where basadas en nuestro código.

Principio: la clase de entidad contiene dos criterios con una relación de herencia y los métodos generados automáticamente se utilizan para construir condiciones de consulta. Pase esta clase de entidad que contiene Criterios como parámetro al parámetro de consulta y se convertirá en condiciones SQL al analizar el asignador Mapper.

Agregar archivo de configuración

<?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>

agregar complemento

Agregue el complemento correspondiente en 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>

generar

El complemento de ejecución en el proyecto maven nos ayuda a generar rápidamente los archivos relevantes correspondientes a la estructura de tabla requerida.

Mapeador universal

Cuando los campos de nuestra tabla cambian, necesitamos modificar los campos y métodos definidos en la clase de entidad y el archivo Mapper. Si se trata de mantenimiento incremental, modifique los archivos uno por uno. Si se trata de un reemplazo completo, también debemos comparar los archivos generados con MBG. Cada vez que un campo cambia, es necesario modificarlo una vez, lo cual es muy problemático de mantener.

método uno

Porque el Mapper de MyBatis admite la herencia. Por lo tanto, tanto Mapper.xml como la interfaz Mapper se pueden dividir en dos archivos. Uno es generado por MBG y esta parte está arreglada. Luego cree una clase DAO que herede la interfaz generada y las partes modificadas se mantengan en DAO.

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

Archivo de mapeo correspondiente

<?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>

En el archivo de configuración global también necesitamos escanear

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

Entonces, en el futuro, solo necesitarás modificar el archivo Ext. Una desventaja de hacer esto es que los archivos aumentarán.

Método 2

Dado que los métodos básicos generados para cada tabla son los mismos, es decir, la parte del método público del código es la misma, ¿se puede fusionar esta parte en un archivo y hacer que admita genéricos?

Escriba una interfaz general que admita genéricos, como GPBaseMapper, y pase la clase de entidad como parámetro. Esta interfaz define una gran cantidad de métodos básicos para agregar, eliminar, modificar y consultar, y todos estos métodos admiten genéricos.

Una interfaz Mapper personalizada hereda esta interfaz general, como BlogMapper extiende GPBaseMapper y obtiene automáticamente métodos de operación para clases de entidad. Si encontramos métodos que no existen, aún podemos escribirlos en nuestro propio Mapper.

La solución que se puede pensar ya la ha hecho alguien: esto se llama universal Mapper .

Propósito: Resuelve principalmente el problema de agregar, eliminar, modificar y consultar una sola tabla, no es adecuado para escenarios de consulta relacionados con varias tablas.

Además del problema de los cambios en el archivo de configuración, Universal Mapper también puede resolver:

  1. Una gran cantidad de definiciones de métodos repetidas en cada interfaz de Mapper;
  2. Enmascarar diferencias en bases de datos;
  3. Proporcionar métodos para operaciones por lotes;
  4. Implementar paginación.

Uso: cuando se usa en Spring, introduzca el paquete jar y reemplace sqlSessionFactory y configúrelo en applicationContext.xml.

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

MyBatis-Plus

MyBatis-Plus es una herramienta mejorada para MyBatis nativo. Puede utilizar las funciones únicas de plus basándose en el uso de todas las funciones del MyBatis nativo.

Funciones principales de MyBatis-Plus:

CRUD universal : Después de definir la interfaz Mapper, solo necesita heredar la interfaz BaseMapper para obtener las funciones universales de agregar, eliminar, modificar y consultar sin escribir ningún método de interfaz ni archivos de configuración.

Constructor condicional : a través de EntityWrapper (clase contenedora de entidad), se puede utilizar para unir declaraciones SQL y admite SQL complejo, como ordenar y agrupar consultas.

Generador de código : admite una serie de configuraciones de políticas y configuraciones globales, que es más utilizable que la generación de código MyBatis.

Supongo que te gusta

Origin blog.csdn.net/qq_28314431/article/details/133087651
Recomendado
Clasificación