Guía práctica de MyBatis: explorando el arte de la persistencia flexible

Directorio de artículos


prefacio

En el campo del desarrollo de software, la elección del marco de la capa de persistencia juega un papel vital en la realización y mantenimiento del proyecto. Como excelente marco de capa de persistencia, MyBatis se ha preocupado y aplicado ampliamente por su flexibilidad, alto grado de personalización y control directo sobre SQL. Este artículo explorará en profundidad el marco MyBatis, desde el conocimiento inicial hasta la aplicación práctica, y revelará gradualmente su papel clave en el desarrollo de software moderno.

1. Conociendo MyBatis por primera vez

1.1 ¿Qué es MyBatis?

MyBatis es un excelente marco de capa de persistencia Java de código abierto, que se utiliza para simplificar el proceso de acceso y operación de la base de datos. Permite a los desarrolladores utilizar un método simple XML或注解配置para mapear la relación entre los objetos Java y las tablas de la base de datos, a fin de lograr la operación persistente de la base de datos. MyBatis no es un marco ORM (mapeo relacional de objetos) integral, sino que pone más énfasis en el control preciso de SQL, lo que permite a los desarrolladores escribir y optimizar declaraciones SQL de manera más directa.

Marco ORM (Object-Relational Mapping):
ORM, el nombre completo de Object-Relational Mapping (Object-Relational Mapping), es una tecnología de software que se utiliza para combinar modelos de objetos en lenguajes de programación orientados a objetos (como Java, Python, etc.) Mapeo y transformación entre modelos de datos en la base de datos. En pocas palabras, el marco ORM permite a los desarrolladores utilizar el pensamiento orientado a objetos para operar bases de datos sin escribir declaraciones SQL directamente.

La idea central de MyBatis radica en la descomposición de SQL, que 将 SQL 语句与 Java 代码se separa, reduciendo así el acoplamiento del código y proporcionando mayor flexibilidad y mantenibilidad . Al configurar el archivo de mapeo (Mapper XML), los desarrolladores pueden definir claramente la relación de mapeo entre las declaraciones SQL y los resultados de la consulta, mientras que el código Java se centra en escribir la lógica empresarial. Además, MyBatis también admite funciones como SQL dinámico, enlace de parámetros y almacenamiento en caché, lo que hace que las operaciones de la base de datos sean más eficientes y convenientes.

1.2 ¿Por qué aprender MyBatis?

Para el desarrollo de back-end, el programa se compone de las siguientes dos partes importantes, a saber, el programa de back-end y la base de datos.


Para que estos dos componentes importantes se comuniquen, deben confiar en herramientas de conexión de bases de datos, como el JDBC anterior y el marco MyBatis actual, tanto para conectar como para operar la base de datos.
Sin embargo, la operación de usar JDBC será muy engorrosa, por lo que deberá utilizar otros métodos de conexión de bases de datos más simples y eficientes, y MyBatis es una mejor opción.

Como marco de capa de persistencia, MyBatis tiene muchas ventajas y valores en el desarrollo de software moderno. Las principales razones para aprender MyBatis son:

1. Control SQL flexible: MyBatis permite a los desarrolladores escribir y controlar directamente declaraciones SQL, lo cual es muy útil para escenarios que requieren control preciso y optimización de las operaciones de la base de datos. Los desarrolladores pueden escribir sus propias declaraciones SQL y ajustarlas según necesidades específicas sin estar limitados por el SQL generado automáticamente.

2. Buen rendimiento: dado que los desarrolladores pueden optimizar las declaraciones SQL para hacerlas más adecuadas para requisitos específicos de consultas y bases de datos, MyBatis tiene un rendimiento excelente. Las declaraciones SQL correctamente escritas y optimizadas pueden mejorar significativamente la eficiencia del acceso a la base de datos de las aplicaciones.

3. Adáptese a diferentes bases de datos: MyBatis admite una variedad de bases de datos, por lo que no importa qué base de datos relacional (como MySQL, Oracle, SQL Server, etc.) se utilice, MyBatis puede adaptarse y proporcionar un modo de operación consistente.

4. Buena escalabilidad: MyBatis permite a los desarrolladores escribir TypeHandlers, complementos, etc. personalizados para satisfacer necesidades específicas, mejorando así la escalabilidad y personalización del marco.

5. Marco liviano: en comparación con algunos marcos ORM pesados, MyBatis es un marco relativamente liviano con bajos costos de aprendizaje y relativamente fácil de usar.

6. Se puede integrar con otros marcos: MyBatis se puede integrar fácilmente con otros marcos populares (como Spring, Spring Boot), lo que hace que el proceso general de desarrollo sea más fluido.

7. Comprenda mejor la base de datos: al aprender MyBatis, no solo aprenderá un marco, sino que también tendrá una comprensión más profunda del método de trabajo y el método de optimización del rendimiento de la base de datos, lo cual es muy útil para el diseño de bases de datos y la optimización de aplicaciones.

2. El posicionamiento de MyBatis en el marco de desarrollo de software.

Es muy importante comprender el posicionamiento de MyBatis en todo el marco de desarrollo de software, especialmente para comprender su papel y su papel en la arquitectura del sistema. El siguiente es un diagrama de flujo interactivo simple que muestra la posición y la interacción de MyBatis en toda la arquitectura de la aplicación:

En el proceso anterior, MyBatis se ubica principalmente en la capa de persistencia (Persistencia), y su función es encapsular y gestionar la interacción entre la lógica empresarial y la base de datos . La siguiente es la interacción entre las capas:

  1. Interfaz front-end : esta es la interfaz de usuario de la aplicación a través de la cual el usuario interactúa con el sistema y envía solicitudes.

  2. Capa de control (Controlador) : la capa de control recibe solicitudes de la interfaz de usuario, maneja la distribución y programación de las solicitudes y llama a la capa de servicio adecuada para el procesamiento comercial.

  3. Capa de servicio (Servicio) : La capa de servicio contiene la lógica empresarial de la aplicación. Recibe solicitudes pasadas por la capa de control, procesa la lógica empresarial y es posible que necesite interactuar con la capa de persistencia para obtener datos.

  4. Capa de persistencia (Persistencia - MyBatis) : MyBatis se encuentra en la capa de persistencia, que es responsable de convertir los requisitos de acceso a datos en la lógica empresarial en operaciones en la base de datos. A través de archivos de mapeo (Mapper XML) y las interfaces correspondientes (Mapper Interface) para mapeo relacional , MyBatis gestiona la conversión de datos entre objetos Java y tablas de bases de datos.

  5. Base de datos (DB) : la base de datos es donde se almacenan los datos reales. MyBatis realiza operaciones reales de la base de datos a través de declaraciones SQL y refleja operaciones como el almacenamiento, recuperación y actualización de datos de la base de datos.

En este proceso, MyBatis actúa como un puente en la capa de persistencia, responsable de conectar la lógica empresarial con las operaciones de la base de datos . Permite a los desarrolladores definir la relación entre las tablas de la base de datos y los objetos Java a través de archivos de mapeo o anotaciones, para lograr el acceso a los datos. Este posicionamiento permite a los desarrolladores aprovechar al máximo el rendimiento y la funcionalidad de la base de datos mientras mantienen la capacidad de mantenimiento y la escalabilidad del código.

3. Cree un proyecto MyBatis basado en Spring Boot

3.1 Agregar soporte para el marco MyBatis

  1. Crear un proyecto Spring Boot

  1. Agregar dependencia MyBatis

Al crear un proyecto Spring Boot, si desea crear un proyecto MyBatis, debe verificarlo en las dependencias y, MyBatis Frameworkademás, debe verificar un controlador de base de datos específico, como MySQL Driver.

3.2 Configurar la información de conexión de la base de datos y la ruta de almacenamiento del archivo de mapeo (Mapper XML)

Después de crear el proyecto Spring Boot, también debe configurar application.ymlla información de conexión de la base de datos y la ruta de almacenamiento del archivo de mapeo (Mapper XML) para MyBatis en el archivo de configuración.

El contenido de la configuración es el siguiente:

# 配置数据库的连接字符串
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/database?characterEncoding=utf8
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

Esta parte de la configuración se utiliza para establecer la información de conexión de la base de datos. urlDebe modificar los campos y según la situación real para conectarse a su propia base de datos MySQL username. passwordEl driver-class-namecampo especifica el nombre de clase del controlador de la base de datos MySQL.

# 设置 Mybatis 的 xml 保存路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml

Esta parte de la configuración establece Mapper XMLla ruta para guardar el archivo. mapper-locationsEl campo especifica que MyBatis debe classpath:mapper/buscar archivos en la ruta Mapper XML. MyMapperPrimero, debe crear un archivo correspondiente a la interfaz en esta ruta Mapper XMLantes de poder usar MyBatis.

Cuarto, la creación y uso de la estructura del proyecto MyBatis.

4.1 Preparación de base de datos y tablas.

userinfoCrea una tabla y articleinfotablas aquí :

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
use mycnblog;

-- 创建表[用户表]
drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';


-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
(1, 'admin', 'admin', '', '2023-8-09 10:10:48', '2023-8-09 10:10:48', 1);

-- 文章添加测试数据
insert into articleinfo(title,content,uid) values('Java','Java正文',1);
insert into articleinfo(title,content,uid) values('C++','C++正文', 1);
insert into articleinfo(title,content,uid) values('Python','Python', 1);
insert into articleinfo(title,content,uid) values('PHP','PHP正文', 1);

4.2 Crear clases de entidad basadas en tablas de bases de datos

userinfoPor ejemplo, cree una clase de entidad para una tabla :

@Data
public class UserInfo {
    
    
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

Los nombres de los atributos en la clase de entidad generalmente coinciden con los campos en la tabla de la base de datos para una mejor compatibilidad. Aquí, las anotaciones en la biblioteca de Lombok se utilizan @Datapara generar automáticamente métodos como getter, setter, equals, hashCode y toString de la clase de entidad, lo que puede reducir la escritura de código repetitivo.

4.3 Crear interfaz Mapper y archivo de mapeo XML

La clase de entidad anterior ya contiene los atributos correspondientes a los campos de la tabla de la base de datos y los tipos de datos correspondientes. Solo asegúrese de que la interfaz y la documentación coincidan correctamente con la clase de entidad MyBatiscuando se utilicen. Puede crear una interfaz y un archivo correspondientes y luego usar anotaciones para marcar la interfaz.MapperMapper XMLMapperXML@Mapper

mapperCree una interfaz en el directorio UserMapper:


Entre ellos, @Mapperla anotación es una anotación en MyBatis, que se utiliza para marcar una interfaz Mapper cuya interfaz es MyBatis, para decirle a MyBatis que esta interfaz define el método de operación de la base de datos. En esta interfaz, solo necesita escribir código relacionado con las operaciones de la base de datos, por ejemplo, para obtener toda Userla información:

import com.example.demo.entity.UserInfo;

import java.util.List;

@Mapper
public interface UserInfoMapper {
    
    
    List<UserInfo> getAll();
}

Cree un archivo de mapeo XML:

  1. Primero resourcescree un mappersubdirectorio en el directorio para almacenar Mapper XMLarchivos:

  2. mapperCree UserInfoMapper.javaun archivo XML correspondiente a la interfaz en esta ruta UserInfoMapper.xml:

  1. Luego necesitas llenar este archivo con el siguiente contenido:
<?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.example.demo.mapper.UserInfoMapper">
    
</mapper>

Entre ellos namespace, el campo especifica la ruta de la interfaz UserInfoMapper.xmlcorrespondiente UserInfoMapper. En este momento, se establece la relación de mapeo entre el archivo XML y la interfaz.

Cuando el complemento está instalado en IDEA MyBatisX, puede encontrar un par de pájaros. En este momento, haga clic en UserInfoMapper.xmlel pájaro azul en el costado para ajustarlo a UserInfoMapperla interfaz asignada.

Por el contrario, al hacer clic UserInfoMapperen el pájaro rojo en la interfaz también se saltará al UserInfoMapper.xmlarchivo correspondiente.

En este momento, se descubre que el método en la interfaz informará un error porque Mapper XMLno hay una declaración SQL correspondiente en el archivo.

Implemente la declaración SQL correspondiente al método getAll:

Al UserInfoMapper.xmlescribir una declaración SQL para consultar a todos los usuarios:


Entre ellos, idel campo especifica el método en la interfaz Mapper correspondiente a esta declaración SQL, es decir getAll, resultTypeel campo es el tipo de datos devueltos y el objeto devuelto aquí UserInfo, el marco MyBatis se configurará de acuerdo con este mapeo. Cuando se completa la ejecución, los resultados de la consulta se asignan automáticamente a UserInfoobjetos. Pero el requisito previo es garantizar que los nombres de los atributos en la clase de entidad coincidan con los nombres de los campos de la tabla de la base de datos, para que MyBatis pueda asignar correctamente los resultados.

4.4 Crear capa de servicio Capa de servicio y control Controlador

  1. Cree un servicedirectorio de capa de servicio y cree clases en ese directorio UserInfoService:
@Service
public class UserInfoService {
    
    
    @Autowired
    private UserInfoMapper userInfoMapper;

    public List<UserInfo> getAll(){
    
    
        return userInfoMapper.getAll();
    }
}
  1. Cree un controllerdirectorio de capa de control y luego cree una clase en ese directorio UserInfoController:
@RequestMapping("/user")
@RestController
public class UserInfoController {
    
    
    @Autowired
    private UserInfoService userInfoService;

    @GetMapping("/getAll")
    public List<UserInfo> getAll(){
    
    
        return userInfoService.getAll();
    }
}

En este punto, se ha completado la creación de la capa de servicio y la capa de control. La capa de control es responsable de procesar las solicitudes HTTP y la interacción con los usuarios y la capa de servicio, mientras que la capa de servicio se utiliza para procesar la lógica de negocios relacionada con el usuario. información y proporcionar Devolver el resultado del procesamiento. Esta estructura se ajusta al patrón de diseño típico de arquitectura de tres niveles (Controlador - Servicio - Repositorio/DAO), lo que hace que el código sea más claro y fácil de mantener.

En el código anterior, UserInfoServicees responsable de llamar para UserInfoMapperrealizar operaciones de base de datos y UserInfoControlleres responsable de procesar solicitudes HTTP, separando la lógica empresarial de las operaciones de la base de datos.

En esta estructura básica, se permite obtener /user/getAlltoda la información del usuario a través del acceso, por ejemplo, ejecute el servidor en este momento y luego ingrese en el navegador http://localhost:8080/user/getAllpara acceder, puede ver que se ha obtenido toda la información del usuario en la base de datos:

5. Agregar, eliminar y modificar operaciones a través de MyBatis

5.1 Agregar usuarios

1. UserInfoMapperAgregue un addUsermétodo a la interfaz:

// 增加用户
int addUser(UserInfo user);

2. UserInfoMapper.xmlEscriba la declaración SQL correspondiente en:

<insert id="addUser">
    insert into userinfo(username, password) values (#{username}, #{password})
</insert>

3. En este punto, puede realizar addUseruna prueba unitaria del

UserInfoMapper1) Primero haga clic derecho en la interfaz y luego seleccione Generate:

2) Seleccione uno de ellos Test:

3) Cree una clase de prueba unitaria


Seleccione Agregar addUsermétodo de prueba aquí. Una vez completada la adición, puede testencontrar la clase de prueba correspondiente en el directorio:


4) Escribir código de prueba


Explicación sencilla:

  • En el código de prueba, @SpringBootTestse utilizan anotaciones para indicar que se trata de una prueba de Spring Boot.
  • @AutowiredLa anotación se utiliza para inyección automática UserInfoMapper, lo que permite su uso en pruebas.
  • @TransactionalLas anotaciones se utilizan para representar operaciones transaccionales durante la prueba, que se revertirán al final de la prueba para evitar un impacto real en la base de datos.

Ejecute el código de prueba y descubra que pasa la prueba, lo que indica que el código de ahora es correcto:

5.2 Modificar usuario

idPor ejemplo, en este momento debe modificar el nombre de usuario a través del usuario:

1. UserInfoMapperAgregue un updateUserByIdmétodo a la interfaz:

// 根据id修改用户名
int updateUserById(Integer id, String username);

2. UserInfoMapper.xmlEscriba la declaración SQL correspondiente en:

<update id="updateUserById">
    update userinfo set username=#{username} where id=#{id}
</update>

3. Ejecute pruebas unitarias:

1) Agregar método de prueba

@Test
void updateUserById() {
    
    
}

2) Escribir código de prueba

En este momento, userinfoel contenido de la tabla es:

Es necesario idcambiar el nombre de usuario cuyo valor es 1 a admin:

@Test
void updateUserById() {
    
    
    Integer id = 1;
    String username = "admin";
    int res = userInfoMapper.updateUserById(id, username);
    System.out.println("影响行数:" + res);
}

3) Ejecutar el método de prueba.

Ejecución exitosa:

verifique la tabla nuevamente userinfoy descubra que la modificación se realizó con éxito:

5.3 Eliminar usuario

Ahora, solicite ideliminar el usuario especificado por usuario:

1. UserInfoMapperAgregue un deleteUserByIdmétodo a la interfaz:

// 根据 id 删除用户
int deleteUserById(Integer id);

2. UserInfoMapper.xmlEscriba la declaración SQL correspondiente en:

<delete id="deleteUserById">
    delete from userinfo where id=#{id}
</delete>

3. Ejecute pruebas unitarias:

1) Agregar método de prueba

@Test
void deleteUserById() {
    
    
}

2) Escribe el método de prueba.

Para eliminar idel usuario que tiene 12 años en este momento:

    @Test
    void deleteUserById() {
    
    
        Integer id = 12;
        int res = userInfoMapper.deleteUserById(id);
        System.out.println("影响行数:" + res);
    }

3) Ejecute el código de prueba

Prueba aprobada:

userinfoSe descubre que el usuario con 12 en la tabla idse elimina en este momento :

6. Realizar la operación de consulta a través de MyBatis

6.1 Consulta de tabla única

6.1.1 Consulta por ID de usuario

1. UserInfoMapperAgregue getUserByIdun método a la interfaz:

// 根据id查询用户
UserInfo getUserById(Integer id);

2. UserInfoMapper.xmlEscribe el SQL correspondiente en:

Utilice #{}marcadores de posición de parámetros:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id=#{id}
</select>

Utilice ${}marcadores de posición de parámetros:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id=${id}
</select>

3) Ejecutar pruebas unitarias

Consulta idpara usuarios con 1:

@Test
void getUserById() {
    
    
    UserInfo user = userInfoMapper.getUserById(1);
    System.out.println(user);
}

Ejecute resultados utilizando #{}marcadores de posición de parámetros:

El resultado de usar ${}el marcador de posición del parámetro:

no es difícil encontrarlo a través del código de prueba anterior:

  • Cuando se utiliza #{}el marcador de posición del parámetro, la posición del parámetro en la instrucción SQL que se ejecutará es ?, es decir, ha sido precompilado por SQL y debe asignarse ?más adelante;
  • Cuando se utiliza ${}el marcador de posición del parámetro, el parámetro se reemplaza directamente.

6.1.2 Marcadores de posición de parámetros #{} y ${}

En MyBatis, #{}y ${}hay dos marcadores de posición de parámetros de uso común para hacer referencia a valores de parámetros en declaraciones SQL. Aunque parecen similares, existen algunas diferencias importantes cuando se usan.

1. #{}Marcadores de posición:

  • #{}Cuando se utiliza el marcador de posición en la declaración SQL, podrá 自动进行预编译,防止 SQL 注入攻击manejar la conversión de tipo del parámetro. Funciona con la mayoría de los parámetros SQL como cadenas, números, etc.

2. ${}Marcadores de posición:

  • ${}Los marcadores de posición se utilizan cuando se utilizan en sentencias SQL 将参数值直接嵌入到 SQL 语句中,不进行预编译. Esto puede suponer un riesgo de inyección de SQL y debe utilizarse con precaución. Es adecuado para algunos escenarios especiales, como nombres de tablas dinámicas o nombres de columnas, etc.

#{}Por lo tanto, se recomienda utilizar marcadores de posición tanto como sea posible en la mayoría de los casos para garantizar la seguridad y la mantenibilidad de SQL. ${}Utilice marcadores de posición solo cuando sea necesario , garantizando al mismo tiempo la legalidad y seguridad de los parámetros de entrada.

6.1.3 Problemas de inyección SQL

${}El siguiente problema de inyección SQL ocurre cuando se utiliza el inicio de sesión simulado:

1. UserInfoMapperAgregue getUserByIdun método a la interfaz:

// 实现登录操作
UserInfo login(UserInfo user);

2. UserInfoMapper.xmlEscribe el SQL correspondiente en:

<select id="login" resultType="com.example.demo.entity.UserInfo">
	select * from userinfo where username='${username}' and password='${password}'
</select>

Dado que el uso ${}es un reemplazo directo de parámetros, es necesario ${}agregarlo afuera ''.

3. Escribe pruebas unitarias

Primero una demostración normal:

@Test
void login(){
    
    
    String username = "zhangsan";
    String password = "123456";
    UserInfo user = new UserInfo();
    user.setUsername(username);
    user.setPassword(password);
    UserInfo loginUser = userInfoMapper.login(user);
    System.out.println(loginUser);
}

En este punto, el objeto se puede obtener con éxito:

Pero si passwordcambias a:

String password = "'  or 1='1";

Ejecute el código de prueba nuevamente:


Se descubre que en este momento se obtuvo todo el contenido de la base de datos y la declaración SQL ejecutada es:

select * from userinfo where username='zhangsan' and password='' or 1='1'

Es decir, independientemente de si la entrada usernamey passwordes correcta, wherela condición siempre es verdadera true, lo que supone el riesgo de inyección SQL.

Si ${}cambia a #{}:


<select id="login" resultType="com.example.demo.entity.UserInfo">
	select * from userinfo where username=#{username} and password=#{password}
</select>

Ejecute el código anterior nuevamente:

En este momento, al precompilar y luego obtener parámetros, se evita el riesgo de inyección SQL.

6.1.3 consulta similar

Utilice likeconsulta difusa por nombre de usuario:
1. UserInfoMapperAgregue getListByNameun método a la interfaz:

// like 模糊查询
List<UserInfo> getListByName(@Param("username") String username);

2. UserInfoMapper.xmlEscribe el SQL correspondiente en:

Utilice #{}marcadores de posición de parámetros:

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like '%#{username}%'
</select>

En este momento, a través de la prueba unitaria, se descubre que se informará un error al final:


Esto se debe a que cuando se usa #{}, la declaración SQL resultante es:

select * from userinfo where username like '%'ang'%'

Y esta es una declaración SQL incorrecta, todos informarán un error, por lo que likecuando use la consulta, debe usar ${}el marcador de posición del parámetro para el reemplazo directo .

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like '%${username}%'
</select>

Ejecute el código de prueba nuevamente y descubra que se puede encontrar correctamente:


Sin embargo, todavía hay un problema de inyección SQL, por lo que aún es necesario usarlo #{}. Para esta situación, puede usar la función incorporada de MySQL concatpara resolverlo:

<select id="getListByName" resultMap="BaseMap">
    select *
    from userinfo
    where username like concat('%', #{
    
    username}, '%');
</select>

Entre ellos, concatla función es unir cadenas y admitir parámetros variables.

6.1.4 Utilice resultMap para resolver la falta de coincidencia entre los parámetros de clase de entidad y los campos de la tabla de base de datos

A veces, es posible que el nombre del parámetro en la clase de entidad en nuestro programa no coincida con el nombre del campo en la tabla de la base de datos, entonces MyBatis no puede vincular correctamente el resultado de la consulta al objeto de clase de entidad, lo que se puede resolver usando en este caso Mapper XML.resultMap

Por ejemplo, userinfoel campo de contraseña en la tabla es passwordy el nombre del atributo en la clase de entidad se llama pwd. En este momento, getUserByIdse consulta al usuario y finalmente pwdse encuentra que el atributo está vacío:


En este punto, UserInfoMapper.xmlagregue una nueva resultMapetiqueta al archivo:

Explicación sencilla:

  • <id>Elementos: Mapas que definen claves primarias. columnEl atributo especifica el nombre de la columna de la tabla de la base de datos y propertyel atributo especifica el nombre del atributo de la clase de entidad. En este ejemplo, la columna de clave principal "id" de la tabla de la base de datos se asigna al atributo "id" de la clase de entidad.

  • <result>Elemento: define el mapeo de columnas comunes. columnEl atributo especifica el nombre de la columna de la tabla de la base de datos y propertyel atributo especifica el nombre del atributo de la clase de entidad. En este ejemplo, la columna "nombre de usuario" de la tabla de la base de datos se asigna al atributo "nombre de usuario" de la clase de entidad, la columna "contraseña" se asigna al atributo "contraseña" de la clase de entidad y la columna "foto" se asigna al atributo "foto" de la clase de entidad.

Luego modifique getUserByIdel SQL correspondiente al método y modifique el resultado devuelto para que sea una asignación de diccionario baseMap:

<select id="getUserById" resultMap="baseMap">
    select * from userinfo where id=${id}
</select>

Ejecute el código de prueba nuevamente para obtener el resultado correcto:

passwordPor supuesto, también puede cambiar el nombre en la declaración SQL pwdpara resolver este problema, por ejemplo:

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select id, username, password as pwd, photo, createtime, updatetime, state 
    from userinfo where id=${id}
</select>

En este momento también se puede obtener el resultado correcto:

6.2 Consulta de varias tablas

6.2.1 Creación de clase VO

Al realizar consultas representativas, normalmente es necesario crear un objeto de valor (VO, objeto de valor) para contener información sobre varias tablas. La clase VO es una clase Java, generalmente utilizada para encapsular los atributos de múltiples clases de entidad, a fin de facilitar la transferencia y el procesamiento de datos en múltiples consultas de tablas.

Por ejemplo, en este momento, debe consultar los detalles del artículo a través del artículo id, y los detalles del artículo deben contener el nombre de usuario, pero articleInfosolo hay usuarios en la tabla uid, por lo que debe realizar una consulta de varias tablas. Para facilitar la combinación de nombre de usuario e información del artículo, ArticleInfoVOes necesario crear una clase adicional.

Primero cree articleinfola clase de entidad correspondiente a la tabla ArticleInfo:

Luego herede esta clase y vocree una ArticleInfoVOclase en el directorio:

6.2.2 Crear interfaz Mapper y archivo de mapeo XML

1. Cree una interfaz Mapper ArticleInfoVOMapper:

2. Cree un archivo de mapeo XML ArticleInfoVOMapper.xml:

6.2.3 Consultar detalles del artículo

1. ArticleInfoVOMapperCree un método en la interfaz getDetial:

// 通过文章 id 查询文章详情
ArticleInfoVO getDetial(Integer id);

2. ArticleInfoVOMapper.xmlEscriba la declaración SQL correspondiente en el archivo:

<select id="getDetial" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a 
        left join userinfo u on a.uid = u.id 
                           where a.id = #{id}
</select>

3. Escribe pruebas unitarias

@SpringBootTest
class ArticleInfoVOMapperTest {
    
    

    @Autowired
    private ArticleInfoVOMapper articleInfoVOMapper;

    @Test
    void getDetail() {
    
    
        ArticleInfoVO detail = articleInfoVOMapper.getDetail(1);
        System.out.println(detail);
    }
}

Ejecute el código de prueba y descubra que el resultado se puede encontrar correctamente:

7. El uso de SQL dinámico MyBatis

MyBatis SQL dinámico se refiere al proceso de generar dinámicamente consultas SQL o declaraciones de actualización de acuerdo con diferentes condiciones y parámetros . Permite el ensamblaje dinámico de varias partes de declaraciones SQL según las necesidades comerciales al escribir archivos de mapeo SQL, logrando así operaciones de base de datos más flexibles. SQL dinámico es muy útil para manejar diferentes condiciones de consulta, ordenar, filtrar, etc. Puede evitar escribir una gran cantidad de declaraciones SQL repetidas debido a múltiples situaciones, mejorando así la eficiencia del desarrollo.

MyBatis proporciona una serie de etiquetas XML y sintaxis para crear SQL dinámico. Estas etiquetas se pueden utilizar para incluir operaciones como juicio condicional, recorrido de bucle y empalme dinámico de fragmentos de SQL. Algunas etiquetas SQL dinámicas de uso común incluyen ,,,,,,,, etc. Para obtener más información , consulte el sitio web oficial de MyBatis: <if>SQL dinámico .<choose><when><otherwise><trim><where><set><foreach>

En resumen, MyBatis Dynamic SQL es un mecanismo poderoso que hace que sea más flexible y conveniente generar declaraciones SQL apropiadas de acuerdo con diferentes situaciones en el archivo de mapeo SQL. La siguiente es una introducción detallada a algunas etiquetas SQL dinámicas comunes.

7.1 si etiqueta

<if>Las etiquetas se utilizan para agregar juicios condicionales en declaraciones SQL y generar dinámicamente fragmentos de SQL de acuerdo con las condiciones verdaderas o falsas.

Por ejemplo, al agregar información del usuario, photoes posible que el usuario no ingrese el contenido del campo. En este caso, debe usar <if>la etiqueta para crear SQL dinámico:

<insert id="addUser">
    insert into userinfo(
    username,
    <if test="photo!=null and photo!=''">
        photo,
    </if>
    password
    )
    values (
    #{username},
    <if test="photo!= null and photo!=''">
        #{photo},
    </if>
    #{pwd}
    )
</insert>

Cabe señalar que el atributo <if>en la etiqueta testespecifica el atributo del objeto pasado, no el campo en la tabla de la base de datos.

En la prueba unitaria, solo ingresa usernamey password, y el SQL final solo tiene estos dos campos:

si agregas un photoatributo:


Se puede encontrar que hay tres campos en este momento.

7.2 etiqueta de ajuste

Si todos los atributos ingresados ​​son opcionales, entonces usar solo <if>la etiqueta no puede resolver ,el problema, porque no sé ,dónde aparecerá, puede aparecer en el frente o puede aparecer en la parte posterior. Si no hay entrada, puede ser que no todo parezca. Por lo tanto, para solucionar este problema es necesario introducir etiquetas <trim>.

<trim>Propiedades de la etiqueta:

  • prefix: Representa el bloque de declaración completo, prefixcon el prefijo del valor de
  • suffix: Indica el bloque de declaración completo, suffixcon el sufijo del valor de
  • prefixOverrides: Indica el prefijo que se eliminará de todo el bloque de declaración.
  • suffixOverrides: Indica el sufijo que se eliminará de todo el bloque de declaración

usernamePor ejemplo, los tres campos , passwordy photoson opcionales al agregar usuarios :

<insert id="addUser">
    insert into userinfo
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="username!=null and username!=''">
            username,
        </if>
        <if test="photo!=null and photo!=''">
            photo,
        </if>
        <if test="pwd!=null and pwd!=''">
            password,
        </if>
    </trim>
    values
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="username!=null and username!=''">
            #{username},
        </if>
        <if test="photo!=null and photo!=''">
            #{photo},
        </if>
        <if test="pwd!=null and pwd!=''">
            #{pwd},
        </if>
    </trim>
</insert>

Entre ellos, <trim>la función de la etiqueta es recortar el nombre de la columna insertada y la parte del valor, y las comas redundantes se pueden eliminar en las posiciones inicial y final. prefixLos atributos representan lo que se agrega antes del fragmento de SQL, suffixlos atributos representan lo que se agrega después del fragmento de SQL y suffixOverrideslos atributos representan lo que se elimina al final del fragmento de SQL.

7.3 donde etiqueta

<where>Las etiquetas se utilizan para agregar condiciones a la cláusula WHERE de una declaración SQL y manejar la lógica entre las condiciones.

Por ejemplo, ahora puede consultar a través iddel o del artículo, donde el contenido de y son entradas opcionales y se utiliza la coincidencia aproximada.titleidtitletitle

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a
    left join userinfo u on a.uid = u.id
    <where>
        <if test="id != null and id > 0">
            and a.id = #{
    
    id}
        </if>

        <if test="title!=null and title!=null">
            and a.title like concat('%', #{
    
    title}, '%')
        </if>
    </where>
</select>

Además, <where>la etiqueta eliminará automáticamente el prefijo and.

Por supuesto, también puedes usar <trim>las <if>etiquetas y para lograr esta funcionalidad:

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
    select a.*, u.username from articleinfo a
    left join userinfo u on a.uid = u.id
    <trim prefix="where" prefixOverrides="and">
        <if test="id != null and id > 0">
            and a.id = #{
    
    id}
        </if>

        <if test="title!=null and title!=null">
            and a.title like concat('%', #{
    
    title}, '%')
        </if>
    </trim>
</select>

En este momento, debe usar <trim>etiquetas para eliminar un prefijo andy agregar un prefijo where.

7.4 establecer etiquetas

<set>Las etiquetas se utilizan para establecer los campos que deben actualizarse en la declaración de actualización y generar dinámicamente la declaración de actualización de acuerdo con las condiciones.

Por ejemplo, idpara modificar nulllos atributos del usuario que no es por el usuario:

<update id="updateById">
    update userinfo
    <set>
        <if test="username!=null and username!=''">
            username=#{
    
    username},
        </if>

        <if test="pwd!=null and pwd!=''">
            password=#{
    
    pwd},
        </if>

        <if test="photo!=null and photo!=''">
            photo=#{
    
    photo},
        </if>
    </set>
    where id=#{
    
    id}
</update>

<set>etiquetas y <where>en su lugar, solo elimina las que tienen sufijo ,.

7.5 etiqueta para cada uno

<foreach>Las etiquetas se utilizan para recorrer una colección o matriz y agregar sus elementos a una declaración SQL.

<foreach>Las etiquetas tienen las siguientes propiedades:

  • collection: La colección en el parámetro del método de enlace, como Lista, Conjunto, Mapa u objeto de matriz.
  • item: cada objeto al atravesar
  • open: La cadena al comienzo del bloque de declaración.
  • close: La cadena al final del bloque de declaración.
  • separator: Una cadena de intervalos entre cada recorrido.

Por ejemplo, ahora necesita ideliminar el artículo correspondiente según varios artículos:

1. ArticleInfoVOMapperAgregue un método a la interfaz:

// 根据多个文章 `id`来删除对应的文章
int deleteByIds(List<Integer> ids);

2. Al ArticleInfoVOMapper.xmlescribir el SQL correspondiente:

<delete id="deleteByIds">
    delete from articleinfo where id in
    <foreach collection="ids" item="item" open="(" close=")" separator=",">
        #{item}
    </foreach>
</delete>

Este código demuestra un ejemplo de cómo construir una declaración de eliminación utilizando SQL dinámico de MyBatis. DELETEEsta declaración de eliminación generará dinámicamente la cláusula en la declaración de acuerdo con la lista de ID dada IN, para eliminar los registros que cumplan la condición en lotes.

Explicación sencilla:

  1. <delete>Etiqueta: esta etiqueta representa la definición de una declaración de eliminación.

  2. <foreach>Etiqueta: esta etiqueta se utiliza para recorrer la colección y agregar los elementos de la colección a la declaración SQL. En este ejemplo, agregaría idscada elemento de la colección a INla cláusula, formando (id1, id2, id3)una estructura como .

    • collectionAtributo: especifica la colección que se va a recorrer.
    • itemAtributo: especifica el alias de cada elemento durante el recorrido.
    • openAtributo: especifique el carácter al comienzo del recorrido, aquí está (.
    • closeAtributo: especifica el carácter al final del recorrido, aquí está ).
    • separatorAtributo: Especifica el separador entre elementos, aquí hay una coma ,.

De esta manera, se puede utilizar SQL dinámico para crear declaraciones de eliminación masiva para eliminar los registros correspondientes en función de un conjunto determinado de ID.

3. Ejecute pruebas unitarias:

@Transactional
@Test
void deleteByIds() {
    
    
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    ids.add(4);
    int res = articleInfoVOMapper.deleteByIds(ids);
    System.out.println("影响行数:" + res);
}

Prueba aprobada:

Supongo que te gusta

Origin blog.csdn.net/qq_61635026/article/details/132172986
Recomendado
Clasificación