Introducción para principiantes de Mybatis-Plus, un artículo es suficiente

Tabla de contenido

1. Introducción a MyBatis-Plus

1. Introducción

2. Características

3. Base de datos de soporte

4. Estructura del marco

5. Dirección oficial

2. Caso introductorio

1. Entorno de desarrollo

2. Crear base de datos y tabla

3. Crea un proyecto

4. Configurar la codificación

1.Mapeador de base

5. Consulta de prueba

Tres, agregar, eliminar, modificar y verificar

1.Mapeador de base

2. Llame a la capa Mapper para implementar CRUD

2.1 insertar

2.2 eliminar

2.3 Modificaciones

2.4 Consulta

3. Servicios generales

4. Capa de servicio de llamadas para operar datos

Cuatro, anotaciones comunes

1. @NombreDeLaTabla

1.1 Conduciendo al problema

1.2 Resolución de problemas

2.@TableId

2.1 Conduciendo al problema

2.2 Resolución de problemas

2.3 El atributo de valor de @TableId

2.4 El atributo de tipo de @TableId

3.@TbaleField

3.1 Caso 1

3.2 Caso 2

4.@TableLogic

4.1 Lápida

4.2 Realizar borrado lógico

5. Constructor de condiciones

1. Introducción a la envoltura

2.Contenedor de consulta

3. Actualizar contenedor

4. parámetro de condición

5.LambdaQueryWrapper

6.Contenedor de actualización de Lambda

Seis complementos de uso común

1. Complemento de paginación

2. Paginación personalizada

3. Cerradura optimista

3.1 Escenarios

3.2 Bloqueo optimista y bloqueo pesimista

3.3 Simular conflictos de modificación

3.4 El bloqueo optimista resuelve el problema

Siete, enumeración general

8. Generador de código

1. Introducir dependencias

2. Generación rápida

Nueve, múltiples fuentes de datos

1. Crear base de datos y tabla

2. Los nuevos proyectos introducen dependencias

3. Escribir archivos de configuración

4. Crear clase de entidad

5. Crear Mapeador y Servicio

6. Escriba el método de prueba

10. Complemento MyBatisX

1. Instala el complemento MyBatisX

2. Genera código rápidamente

3. Genera CRUD rápidamente



1. Introducción a MyBatis-Plus

1. Introducción

MyBatis-Plus (se abre en ventana nueva) (MP para abreviar) es una herramienta de mejora para MyBatis (se abre en ventana nueva) Sobre la base de MyBatis, solo se realizan mejoras sin cambios, y nació para simplificar el desarrollo y mejorar la eficiencia.

Nuestra visión es convertirnos en el mejor socio de MyBatis, al igual que el 1P y 2P en Contra, la eficiencia se duplica cuando se combina con amigos.

2. Características

  • Sin intrusión : solo mejora y sin cambios, la introducción no afectará el proyecto existente, tan suave como la seda.

  • Baja pérdida : el CURD básico se inyectará automáticamente cuando se inicie, el rendimiento es básicamente sin pérdidas y la operación orientada a objetos se realiza directamente

  • Potentes operaciones CRUD : mapeador general y servicio general incorporados, la mayoría de las operaciones CRUD en una sola tabla se pueden realizar con solo una pequeña cantidad de configuración, y hay un potente constructor de condiciones para satisfacer diversas necesidades de uso

  • Admite llamada de formulario Lambda : a través de expresiones Lambda, es conveniente escribir varias condiciones de consulta, sin necesidad de preocuparse por los errores tipográficos de campo

  • Admite la generación automática de claves principales : admite hasta 4 estrategias de claves principales (incluido un generador de ID único distribuido - Secuencia), que se pueden configurar libremente para resolver perfectamente el problema de la clave principal

  • Admite el modo ActiveRecord : admite la llamada de formulario ActiveRecord, la clase de entidad solo necesita heredar la clase Model para realizar potentes operaciones CRUD

  • Admite operaciones generales globales personalizadas : admite inyección de método general global (escribir una vez, usar en cualquier lugar)

  • Generador de código incorporado : use complementos de código o Maven para generar rápidamente códigos de capa de mapeador, modelo, servicio y controlador, admitir motores de plantillas y tener muchas configuraciones personalizadas esperando que las use

  • Complemento de paginación incorporado : basado en la paginación física de MyBatis, los desarrolladores no necesitan preocuparse por operaciones específicas. Después de configurar el complemento, escribir paginación es equivalente a una consulta de lista normal.

  • El complemento de paginación admite múltiples bases de datos : admite MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer y otras bases de datos

  • Complemento de análisis de rendimiento incorporado : puede generar declaraciones SQL y su tiempo de ejecución. Se recomienda habilitar esta función durante el desarrollo y las pruebas, que pueden descubrir rápidamente las consultas lentas.

  • Complemento de intercepción global incorporado : proporciona análisis inteligente y bloqueo de operaciones de eliminación y actualización en toda la tabla, y también puede personalizar las reglas de intercepción para evitar operaciones incorrectas

3. Base de datos de soporte

Cualquier base de datos que pueda MyBatisusar CRUD y admita SQL estándar, el soporte específico es el siguiente, si no está en la lista a continuación, consulte la parte de paginación del tutorial PR para su soporte.

  • MySQL, Oracle, DB2, H2, HSQL, SQLite, PostgreSQL, SQLServer, Phoenix, Gauss, ClickHouse, Sybase, OceanBase, Firebird, Cubrid, Goldilocks, csiidb

  • Base de datos Dameng, Base de datos Xugu, Base de datos Jincang de la Universidad Renmin, Base de datos general Nanda (Huaku), Base de datos general Nanda, Base de datos Shentong, Base de datos Hangao

4. Estructura del marco

Primero escanee la clase de entidad (entidad de escaneo), extraiga los atributos en la clase de entidad a través de la extracción de reflexión (extracción de reflexión) y luego analice quién es la tabla en la que se operará, quién es el atributo en la clase de entidad que se operará y quien es el campo Luego genere la declaración sql e inyéctela en el contenedor mybati La tabla que queremos operar debe estar determinada por la clase de entidad y los atributos de la clase de entidad.

5. Dirección oficial

Web Oficial: MyBatis-Plus

Documento oficial: Introducción | MyBatis-Plus

2. Caso introductorio

1. Entorno de desarrollo

  • IDEA: IDEA 2019.3.5

  • JDK:JDK8+

  • Herramientas de compilación: Maven 3.5.4

  • MySQL:MySQL 8.0.24

  • Navicat:Navicat Premium 15

  • Bota de resorte: 2.6.7

  • MyBatis-Plus:3.5.1

2. Crear base de datos y tabla

  • Abra Navicat y ejecute el siguiente script SQL para crear una base de datos y una tabla

    CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; 
    use `mybatis_plus`; 
    CREATE TABLE `user` ( 
        `id` bigint(20) NOT NULL COMMENT '主键ID', 
        `name` varchar(30) DEFAULT NULL COMMENT '姓名', 
        `age` int(11) DEFAULT NULL COMMENT '年龄', 
        `email` varchar(50) DEFAULT NULL COMMENT '邮箱', 
        PRIMARY KEY (`id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  • Insertar algunos datos de prueba

    INSERT INTO user (id, name, age, email) VALUES 
    (1, 'Jone', 18, '[email protected]'), 
    (2, 'Jack', 20, '[email protected]'), 
    (3, 'Tom', 28, '[email protected]'), 
    (4, 'Sandy', 21, '[email protected]'), 
    (5, 'Billie', 24, '[email protected]');

3. Crea un proyecto

  • Use Spring Initializerla inicialización rápida de un proyecto Spring Boot

  • MyBatis-PlusDependencias importadas

    <!--mybatis-plus启动器-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    ​
        <!-- 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.27</version>
     </dependency>

  • El paquete de dependencias jar más completo Si el último paso de la operación de captura de pantalla anterior no está marcado, puede copiar directamente todas las siguientes dependencias en el archivo prom

    <dependencies>
    ​
        <!--web场景开发启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    ​
    ​
        <!--lombok:简化实体类开发-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    ​
        <!--开启测试启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    ​
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
    ​
        <!-- mybatis-plus启动器-->
        <!-- mybatis-plus 是自己开发,并非官方的! -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
    ​
        <!--多数据源依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
    ​
    </dependencies>

  • instalar Lombokcomplemento

4. Configurar la codificación

  • application.yamlarchivo de configuración

    spring:
      #配置数据库
      datasource:
        # 配置连接数据库信息
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
        username: root
        password: 123456
    ​
    mybatis-plus:
      # 配置MyBatis日志
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    ​
        #全局配置
      global-config:
        db-config:
          #配置统一的主键策略为自增,如果不设置默认为雪花算法
          id-type: auto
          # 设置实体类所对应的表的统一前缀,为实体类所对应的表名设置默认的前缀
          table-prefix: t_
    ​
      #配置mapper映射文件路径,名字要和mapper接口名字一致 这是默认路径不写也行
      mapper-locations: classpath*:/mapper/**/*.xml
    ​
      #配置类型别名所对应的包
      type-aliases-package: com.yka.boot02mybatis_plus.pojo
    ​
      # 扫描通用枚举的包
      type-enums-package: com.yka.boot02mybatis_plus.enums

  • Cree un paquete de configuración para crear una clase de configuración, agregue la anotación @MapperScan`, escanee la carpeta Mapper y agregue la anotación @Configuration**

    @Configuration //告诉SpringBoot这是一个配置类 == spring配置文件
    @MapperScan("com.yka.boot02mybatis_plus.mapper")//扫描接口包 在当前配置类(spring.xml)中填写注解最合适
    //配置mapper接口的扫描配置
    //由mybatis-spring提供,可以将指定包下所有的mapper接口创建代理实现类
    //并将这些动态代理作为IOC容器的bean管理,接口就可以自动装配了,直接可以调用接口中的方法
    public class MyConfig {
    }

  • Escriba la clase de entidad User.java(Lombok se usa aquí para simplificar el código)

    @Data//自动提供get set方法、tosString方法,equals方法
    @AllArgsConstructor//有参构造器
    @NoArgsConstructor//无参构造器
    @TableName("user")//绑定表 yaml文件中设置了全局配置这里可以不用注解了 yaml文件配置文件中:db-config:table-prefix: t_
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }

  • Escriba UserMapperla interfaz

  • 1.BaseMapper<T>

    ilustrar:

    • General CRUD encapsula la interfaz BaseMapper, resuelve automáticamente el mapeo de relaciones de la tabla de entidades al Mybatis-Plusinicio y lo convierte en Mybatisun contenedor de inyección de objetos internos

    • Los genéricos Tson cualquier objeto de entidad

    • El parámetro Serializablees cualquier tipo de clave principal Mybatis-Plus. No se recomienda utilizar una clave principal compuesta. Cada tabla tiene su propia clave idprincipal .

    • el objeto Wrapperes un inicializador condicional

    El CRUD básico en MyBatis-Plus se ha implementado en el BaseMapper incorporado, por lo que podemos usarlo directamente después de heredar esta interfaz.

    La operación CRUD demostrada esta vez no incluye métodos con constructores condicionales como parámetros, y los constructores condicionales se demostrarán en un capítulo separado. Métodos CRUD proporcionados en BaseMapper:

  • // 在对应的Mapper上面继承基本的类 BaseMapper,就能直接用BaseMapper接口里面的sql语句了
    //MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,因此我们继承该接口以后可以直接使用。
    @Repository // 代表持久层
    public interface UserMapper extends BaseMapper<User> {
    // 所有的CRUD操作都已经编写完成了
    // 你不需要像以前的配置一大堆文件了!
    ​
        @Select("select * from user where id = #{id}")
        public User selById(Integer id);
    ​
    }

5. Consulta de prueba

  • escribir una clase de pruebaMyBatisPlusTest.java

    @SpringBootTest
    public class MyBatisPlusTest {
        @Resource
        private UserMapper userMapper;
    ​
        /**
         * 测试查询所有数据
         */
        @Test
        void testSelectList(){
            //通过条件构造器查询一个list集合,若没有条件,则可以设置null为参数
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    }
  • La consola imprime los resultados de la consulta.

Tres, agregar, eliminar, modificar y verificar

1.BaseMapper<T>

ilustrar:

  • General CRUD encapsula la interfaz BaseMapper, resuelve automáticamente el mapeo de relaciones de la tabla de entidades al Mybatis-Plusinicio y lo convierte en Mybatisun contenedor de inyección de objetos internos

  • Los genéricos Tson cualquier objeto de entidad

  • El parámetro Serializablees cualquier tipo de clave principal Mybatis-Plus. No se recomienda utilizar una clave principal compuesta. Cada tabla tiene su propia clave idprincipal .

  • el objeto Wrapperes un inicializador condicional

El CRUD básico en MyBatis-Plus se ha implementado en el BaseMapper incorporado, por lo que podemos usarlo directamente después de heredar esta interfaz.

La operación CRUD demostrada esta vez no incluye métodos con constructores condicionales como parámetros, y los constructores condicionales se demostrarán en un capítulo separado.


Métodos CRUD proporcionados en BaseMapper:

  • Agregado: Insertar

    // 插入一条记录
    int insert(T entity);
  • Eliminar: Eliminar

    // 根据 entity 条件,删除记录
    int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
    // 删除(根据ID 批量删除)
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // 根据 ID 删除
    int deleteById(Serializable id);
    // 根据 columnMap 条件,删除记录
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
  • Modificación: Actualizar

    // 根据 whereWrapper 条件,更新记录
    int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
    // 根据 ID 修改
    int updateById(@Param(Constants.ENTITY) T entity);
  • Consulta: Seleccionar

    // 根据 ID 查询
    T selectById(Serializable id);
    // 根据 entity 条件,查询一条记录
    T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    ​
    // 查询(根据ID 批量查询)
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
    // 根据 entity 条件,查询全部记录
    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 查询(根据 columnMap 条件)
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
    // 根据 Wrapper 条件,查询全部记录
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    ​
    // 根据 entity 条件,查询全部记录(并翻页)
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录(并翻页)
    IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询总记录数
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

2. Llame a la capa Mapper para implementar CRUD

2.1 insertar


El resultado de la ejecución final, la identificación obtenida es 1527206783590903810

Esto se debe a que MyBatis-Plus generará una identificación basada en la estrategia del algoritmo de copo de nieve de forma predeterminada al insertar datos

/**
  * 测试插入一条数据 INSERT INTO user ( name, age, email ) VALUES ( ?, ?, ? )
  * MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id,后面常用注解可以修改
  */
@Test
public void testInsert(){
    User user = new User();
    user.setName("Vz");
    user.setAge(21);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user);
    System.out.println(result > 0 ? "添加成功!" : "添加失败!");
    System.out.println("受影响的行数为:" + result);
    //1527206783590903810(当前 id 为雪花算法自动生成的id)
    System.out.println("id自动获取" + user.getId());
}

2.2 eliminar


a. Eliminar datos según ID

Método de llamada: int deleteById (ID serializable);

/**
  * 测试根据id删除一条数据  DELETE FROM user WHERE id=?
  */
@Test
public void testDeleteById(){
    
    int result = userMapper.deleteById(1527206783590903810L);
    System.out.println(result > 0 ? "删除成功!" : "删除失败!");
    System.out.println("受影响的行数为:" + result);
}

B. Eliminar datos en lotes según ID

Método de llamada: int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

/**
  * 测试通过id批量删除数据  DELETE FROM user WHERE id IN ( ? , ? )
  */
@Test
public void testDeleteBatchIds(){
    List<Long> ids = Arrays.asList(6L,7L,8L);
    int result = userMapper.deleteBatchIds(ids);
    System.out.println(result > 0 ? "删除成功!" : "删除失败!");
    System.out.println("受影响的行数为:" + result);
}
//删除所有数据 DELETE FROM user 
userMapper.delete(null);

c. Eliminar datos de acuerdo con las condiciones del mapa

调用方法:int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

/**
   * 测试根据Map集合中所设置的条件删除数据  
   */
@Test
public void testDeleteByMap(){
    //当前演示为根据name和age删除数据
    //执行SQL为:DELETE FROM user WHERE name = ? AND age = ?
    Map<String,Object> map = new HashMap<>();
    map.put("name","Vz");
    map.put("age",21);
    int result = userMapper.deleteByMap(map);
    System.out.println(result > 0 ? "删除成功!" : "删除失败!");
    System.out.println("受影响的行数为:" + result);
}

2.3 Modificaciones

Método de llamada: int updateById(@Param(Constants.ENTITY) T entidad);

/**
  * 测试根据id修改用户信息
  */
@Test
public void testUpdateById(){
    //执行SQL为: UPDATE user SET name=?, age=?, email=? WHERE id=?
    User user = new User();
    user.setId(6L);
    user.setName("VzUpdate");
    user.setAge(18);
    user.setEmail("[email protected]");
    int result = userMapper.updateById(user);
    System.out.println(result > 0 ? "修改成功!" : "修改失败!");
    System.out.println("受影响的行数为:" + result);
}

2.4 Consulta


a. Consultar información de usuario basada en ID

Método de llamada: T selectById (ID serializable);

/**
  * 测试根据id查询用户数据 SELECT id,name,age,email FROM user WHERE id=?
  */
@Test
public void testSelectById(){
    User user = userMapper.selectById(1L);
    System.out.println(user);
}

b. Consultar información de varios usuarios en función de varios ID

调用方法:List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

/**
  * 根据多个id查询用户数据
  */
@Test
public void testSelectBatchIds(){
    //执行SQL为:SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
    List<Long> ids = Arrays.asList(1L,2L,3L);
    List<User> users = userMapper.selectBatchIds(ids);
    users.forEach(System.out::println);
}

c. Consultar la información del usuario según las condiciones del Mapa

调用方法:List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

/**
  * 根据Map所设置的条件查询用户
  */
@Test
public void testSelectByMap(){
    //执行SQL为:SELECT id,name,age,email FROM user WHERE age = ?
    Map<String,Object> map = new HashMap<>();
    map.put("age",18);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

D. Consultar toda la información del usuario

Método de llamada: List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
  * 测试查询所有数据  SELECT id,name,age,email FROM user
  */
@Test
void testSelectList(){
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}

3. Servicios generales

ilustrar:

  • Interfaz de encapsulación CRUD de servicio general IService, encapsulación adicional CRUD utiliza el método de nomenclatura get 查询单行 remove 删除 list 查询集合 page 分页de prefijo para distinguir Mappercapas para evitar confusiones,

  • Los genéricos Tson cualquier objeto de entidad

  • Se recomienda que, si existe la posibilidad de personalizar el método de servicio general, cree su IBaseServicepropia Mybatis-Plusclase base heredada de la proporcionada

  • el objeto Wrapperes un inicializador condicional

Hay una interfaz IServicey ServiceImpl, que encapsula la lógica de la capa empresarial común; consulte el código fuente IService y ServiceImpl para obtener más información.

Por lo tanto, cuando lo usamos, solo necesitamos Serviceheredar IServicela interfaz en la interfaz que definimos, implementar nuestro propio Servicio en nuestra propia clase de implementación y heredarla ServiceImpl.


Métodos CRUD en IService

  • Agregado: Guardar, Guardar o Actualizar

    // 插入一条记录(选择字段,策略插入)
    boolean save(T entity);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList);
    // 插入(批量)
    boolean saveBatch(Collection<T> entityList, int batchSize);
    ​
    // TableId 注解存在更新记录,否插入一条记录
    //saveOrUpdate:会去表里查该id,如果表里有该id修改,无id是增加,新增不需要id,更改需要id
    boolean saveOrUpdate(T entity);
    // 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
    boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
    // 批量修改插入 会去表里查该id,如果表里有该id修改,无id是增加,新增不需要id,更改需要id
    boolean saveOrUpdateBatch(Collection<T> entityList);
    // 批量修改插入 有id修改无id是增加
    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
  • Eliminar: Quitar

    // 根据 entity 条件,删除记录
    boolean remove(Wrapper<T> queryWrapper);
    // 根据 ID 删除
    boolean removeById(Serializable id);
    // 根据 columnMap 条件,删除记录
    boolean removeByMap(Map<String, Object> columnMap);
    // 删除(根据ID 批量删除)
    boolean removeByIds(Collection<? extends Serializable> idList);
  • Modificación: Actualizar

    // 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
    boolean update(Wrapper<T> updateWrapper);
    // 根据 whereWrapper 条件,更新记录
    boolean update(T updateEntity, Wrapper<T> whereWrapper);
    // 根据 ID 选择修改
    boolean updateById(T entity);
    // 根据ID 批量更新 有id修改无id是增加
    boolean updateBatchById(Collection<T> entityList);
    // 根据ID 批量更新 有id修改无id是增加
    boolean updateBatchById(Collection<T> entityList, int batchSize);
  • Consulta: Obtener, Listar, Contar

    // 根据 ID 查询
    T getById(Serializable id);
    // 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
    T getOne(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    T getOne(Wrapper<T> queryWrapper, boolean throwEx);
    // 根据 Wrapper,查询一条记录
    Map<String, Object> getMap(Wrapper<T> queryWrapper);
    // 根据 Wrapper,查询一条记录
    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
    ​
    ​
    // 查询所有
    List<T> list();
    // 查询列表
    List<T> list(Wrapper<T> queryWrapper);
    // 查询(根据ID 批量查询)
    Collection<T> listByIds(Collection<? extends Serializable> idList);
    // 查询(根据 columnMap 条件)
    Collection<T> listByMap(Map<String, Object> columnMap);
    // 查询所有列表
    List<Map<String, Object>> listMaps();
    // 查询列表
    List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
    // 查询全部记录
    List<Object> listObjs();
    // 查询全部记录
    <V> List<V> listObjs(Function<? super Object, V> mapper);
    // 根据 Wrapper 条件,查询全部记录
    List<Object> listObjs(Wrapper<T> queryWrapper);
    // 根据 Wrapper 条件,查询全部记录
    <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
    ​
    // 查询总记录数
    int count();
    // 根据 Wrapper 条件,查询总记录数
    int count(Wrapper<T> queryWrapper);
  • Paginación: Página

    default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {}

4. Capa de servicio de llamadas para operar datos

En nuestra interfaz de Servicio, al heredar la interfaz IService proporcionada por MyBatis-Plus, no solo podemos obtener los métodos CRUD que proporciona, sino también utilizar los métodos definidos por nosotros mismos.

  • crear UserServicey heredarIService

    /**
      * UserService继承IService模板提供的基础功能 
      */
    public interface UserService extends IService<User> {}
  • UserServiceClase de implementación creada y heredada.ServiceImpl

    /**
      * ServiceImpl实现了IService,提供了IService中基础功能的实现 
      * 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
      */
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{}
  • Número de registros de consulta de prueba

    Método de llamada: int cuenta();

    @Test
    public void testGetCount(){
        //查询总记录数
        //执行的SQL为:SELECT COUNT( * ) FROM user
        long count = userService.count();
        System.out.println("总记录数:" + count);
    }

Cuatro, anotaciones comunes

Las anotaciones que proporciona MyBatis-Plus pueden ayudarnos a resolver algunos problemas de mapeo entre bases de datos y entidades.

1. @NombreDeLaTabla

Después de las pruebas anteriores, al usar MyBatis-Plus para implementar CRUD básico, no especificamos la tabla a operar, sino que configuramos el Usuario genérico cuando la interfaz Mapper heredó BaseMapper, y la tabla operada es la tabla de usuario, por lo que se concluye. que cuando MyBatis-Plus determina la tabla a operar, lo determina el tipo genérico de BaseMapper, es decir, el tipo de entidad, y el nombre de tabla de la operación por defecto es consistente con el nombre de clase del tipo de entidad.

1.1 Conduciendo al problema


Si el nombre de clase del tipo de clase de entidad es inconsistente con el nombre de la tabla que se va a operar, ¿qué problemas ocurrirán?

  • Cambiamos el usernombre de la tabla t_usery probamos la función de consulta.

  • El programa lanza una excepción, la tabla 'mybatis_plus.user' no existe , porque el nombre de la tabla actual t_usery el nombre de la tabla de la operación predeterminada es consistente con el nombre de la clase del tipo de entidad, es decir, userla tabla

1.2 Resolución de problemas

a. Usar anotaciones para resolver problemas

Agréguelo al tipo de clase de entidad @TableName("t_user")para identificar la tabla correspondiente a la clase de entidad, y la declaración SQL se puede ejecutar con éxito

@Data
@TableName("t_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

B. Utilice la configuración global para resolver el problema

En el proceso de desarrollo, a menudo nos encontramos con los problemas anteriores, es decir, las tablas correspondientes a las clases de entidad tienen prefijos fijos, por ejemplo t_o tbl_. correspondiente a la clase de entidad Establezca el prefijo predeterminado, luego no es necesario identificar la tabla correspondiente a la clase de entidad a través de @TableName en cada clase de entidad

mybatis-plus:
  global-config:
    db-config:
      # 设置实体类所对应的表的统一前缀
      table-prefix: t_

2.@TableId

Después de las pruebas anteriores, cuando MyBatis-Plus implemente CRUD, utilizará id como la columna de clave principal de forma predeterminada, y al insertar datos, generará id en función de la estrategia del algoritmo de copo de nieve de forma predeterminada.

2.1 Conduciendo al problema


Si la clase de entidad y la tabla representan la clave principal en lugar de id, pero otros campos, como uid, ¿MyBatis-Plus reconocerá automáticamente uid como la columna de clave principal?

  • Los atributos en nuestra clase de entidad idse cambian uidy los campos en la tabla idtambién se cambian uidpara probar la función de suma.

  • El programa lanza una excepción, el campo 'uid' no tiene un valor por defecto , indicando que MyBatis-Plus no ha asignado uidun valor como clave principal

2.2 Resolución de problemas


Al identificar el atributo uid como la clave principal en la clase de entidad @TableId, la declaración SQL se puede ejecutar con éxito

@Date
public class User {
    //将属性所对应的字段指定为主键
    @TableId
    private Long uid;
    private String name;
    private Integer age;
    private String email;
}

2.3 El atributo de valor de @TableId


Si el atributo correspondiente a la clave principal en la clase de entidad es id, y el campo que representa la clave principal en la tabla es uid, en este momento, si solo se agrega la anotación @TableId a la id del atributo, una excepción columna Desconocida ' id' en 'lista de campos', es decir, MyBatis -Plus seguirá usando id como la clave principal de la tabla, y la clave principal en la tabla es el campo uid. En este momento, debe especificar la clave principal campo clave en la tabla a través del atributo de valor de la anotación @TableId, @TableId("uid")o@TableId(value="uid")

2.4 El atributo de tipo de @TableId


El atributo de tipo se utiliza para definir la estrategia de clave principal: el algoritmo de copo de nieve predeterminado

Estrategias de clave principal de uso común:

valor describir
IdType.ASSIGN_ID (predeterminado) La identificación de datos se genera en función de la estrategia del algoritmo de copo de nieve, independientemente de si la identificación de la base de datos está configurada para incrementar automáticamente
IdType.AUTO Utilice la estrategia de incremento automático de la base de datos. Tenga en cuenta que para este tipo, asegúrese de que la base de datos esté configurada con incremento automático de id.
    
//如果在.yaml文件中设置了全局配置这里就不用再写注解了
    //IdType.ASSIGN_ID(默认)基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
    //@TableId(type = IdType.AUTO,value = "id")//使用数据库的自增策略,注意,该类型请确保数据库设置了id自增,
    // value:如果属性名和字段主键名不一致,可以指定主键字段
    private Long id;

Configure la estrategia de clave principal global: después de la configuración, no es necesario escribir anotaciones en la clase de entidad

#MyBatis-Plus相关配置
mybatis-plus:
  configuration:
    #配置日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      #配置统一的主键策略为自增
      id-type: auto
      # 设置实体类所对应的表的统一前缀
      table-prefix: t_

3.@TbaleField

Después de las pruebas anteriores, podemos encontrar que cuando MyBatis-Plus ejecuta sentencias SQL, debe asegurarse de que los nombres de los atributos en la clase de entidad sean consistentes con los nombres de los campos en la tabla.

Si el nombre del atributo y el nombre del campo en la clase de entidad son inconsistentes, ¿qué sucederá?

3.1 Caso 1


Si los atributos en la clase de entidad usan el estilo de nomenclatura de mayúsculas y minúsculas y los campos en la tabla usan el estilo de nomenclatura de guión bajo

Por ejemplo, atributos de clase de entidad userName, campos en tablasuser_name

En este punto, MyBatis-Plus convertirá automáticamente el estilo de nombre de guión bajo al estilo de nombre de joroba.

Equivale a configurar en MyBatis

3.2 Caso 2


Si los atributos de la clase de entidad y los campos de la tabla no cumplen la condición 1

Por ejemplo, atributos de clase de entidad name, campos en tablasusername

@TableField("username")En este momento, debe usar el nombre de campo correspondiente al atributo de configuración en el atributo de clase de entidad

public class User {
    @TableId("uid")
    private Long id;
    @TableField("username")
    private String name;
    private Integer age;
    private String email;
}

4.@TableLogic

4.1 Lápida


Eliminación física: eliminación real, los datos correspondientes se eliminan de la base de datos y los datos eliminados no se pueden consultar después

Eliminación lógica: Eliminación falsa, modifica el estado del campo que representa si se elimina en los datos correspondientes a "estado eliminado", y luego este registro de datos aún se puede ver en la base de datos

Escenario de uso: la recuperación de datos es posible

4.2 Realizar borrado lógico


  • Cree una columna de estado de lápida en la base de datos, establezca el valor predeterminado en 0, 0 no eliminado, 1 eliminado

  • Agregar atributo de lápida en la clase de entidad

  • Prueba la función de borrado, lo que realmente se realiza es la modificación

    public void testDeleteById(){
        int result = userMapper.deleteById(1527472864163348482L);
        System.out.println(result > 0 ? "删除成功!" : "删除失败!");
        System.out.println("受影响的行数为:" + result);
    }

  • Ejecute el método de consulta en este momento, y el resultado de la consulta es agregar condiciones automáticamenteis_deleted=0,查询的是未删除的数据

5. Constructor de condiciones

1. Introducción a la envoltura

  • Wrapper: clase abstracta construida condicionalmente, la clase principal más alta

  • AbstractWrapper: Se utiliza para encapsular condiciones de consulta y generar condiciones where para sql 

    • QueryWrapper: Encapsulación de condiciones de consulta

    • UpdateWrapper: Actualizar paquete condicional

    • AbstractLambdaWrapper: Usar sintaxis Lambda

      • LambdaQueryWrapper: Query Wrapper para el uso de la sintaxis de Lambda

      • LambdaUpdateWrapper: Envoltorio del paquete de actualización de Lambda

2.Contenedor de consulta

  • Montaje de condiciones de consulta

    @Test
        public void test01(){
            //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
            //查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.like("name","a").between("age",20,30).isNotNull("email");
            List<User> users = userMapper.selectList(queryWrapper);
            users.forEach(System.out::println);
        }

  • Condiciones de clasificación de conjuntos

     @Test
        public void test02(){
            //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,id ASC
            //查询用户信息,按照年龄的降序排序,若年龄相同,则按照id升序排序
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByDesc("age").orderByAsc("id");
            List<User> users = userMapper.selectList(queryWrapper);
            users.forEach(System.out::println);
        }

  • Condición de eliminación de ensamblaje

    执行SQL: ACTUALIZAR t_user SET is_deleted=1 DONDE is_deleted=0 Y (el correo electrónico ES NULO)

    public void test03(){
        //删除邮箱地址为null的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println(result > 0 ? "删除成功!" : "删除失败!");
        System.out.println("受影响的行数为:" + result);
    }

  • modificar función

    @Test
        public void test04(){
            //将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
            //UPDATE t_user SET name=?, email=? WHERE is_deleted=0 AND (age > ? AND name LIKE ? OR email IS NULL)
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.gt("age",20).like("name","a")
                    .or()
                    .isNull("email");
            User user = new User();
            user.setName("小明");
            user.setEmail("[email protected]");
    ​
            int result = userMapper.update(user,queryWrapper);
            System.out.println(result > 0 ? "修改成功!" : "修改失败!");
            System.out.println("受影响的行数为:" + result);
        }

    Prioridad de las condiciones

     @Test
        public void test05(){
            //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
            //UPDATE t_user SET name=?, email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
            //lambda中优先执行,i就是条件构造器queryWrapper .and()和.or()都有lambda表达式
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.like("name","a")
                    .and(i-> i.gt("age",20).or().isNull("email"));
    ​
            User user = new User();
            user.setName("小红");
            user.setEmail("[email protected]");
    ​
            int result = userMapper.update(user, queryWrapper);
            System.out.println(result > 0 ? "修改成功!" : "修改失败!");
            System.out.println("受影响的行数为:" + result);
        }
     
  • Montaje de la cláusula select

    执行SQL: SELECCIONE nombre de usuario, edad, correo electrónico DESDE t_user DONDE is_deleted=0

    @Test
        public void test06(){
            //查询用户的用户名、年龄、邮箱信息
            //SELECT name,age,email FROM t_user WHERE is_deleted=0
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("name","age","email");
            List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
            maps.forEach(System.out::println);
        }

  • implementar la subconsulta

    @Test
        public void test07(){
            //查询id小于等于100的用户信息
            //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (id IN (select id from t_user          where id <= 100))
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.inSql("id", "select id from t_user where id <= 100");
            List<User> list = userMapper.selectList(queryWrapper);
            list.forEach(System.out::println);
        }

3. Actualizar contenedor

UpdateWrapper no solo tiene la función de condición de ensamblaje de QueryWrapper, sino que también proporciona el método set para modificar la información de la base de datos de la condición correspondiente

 @Test
    public void test08(){
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //UPDATE t_user SET name=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.like("name","a")
                .and( i -> i.gt("age",20).or().isNull("email"))
                .set("name","小黑").set("email","[email protected]");//设置修改的字段
​
        int result = userMapper.update(null, updateWrapper);
        System.out.println(result > 0 ? "修改成功!" : "修改失败!");
        System.out.println("受影响的行数为:" + result);
    }

4. parámetro de condición

Si se cumple la condición del parámetro de condición, se ejecuta la condición en el constructor de condición

Simule los parámetros pasados ​​del cliente al servidor durante el desarrollo y la prueba

En el proceso de desarrollo real, ensamblar condiciones es una función común, y estos datos de condiciones provienen de la entrada del usuario y son opcionales. Por lo tanto, cuando ensamblamos estas condiciones, primero debemos determinar si el usuario ha seleccionado estas condiciones. Si es así, necesitamos para Ensamblar la condición, si no hay selección (null), no debe ser ensamblada, para no afectar el resultado de la ejecución del SQL

  • Idea 1 Escritura complicada

    执行SQL: SELECCIONE uid COMO id,nombre_de_usuario COMO nombre,edad,correo electrónico,se_eliminó DE t_usuario DONDE se_eliminó=0 Y (nombre_de_usuario COMO ? Y edad <= ?)

    //复杂写法,模拟开发中客户端传到服务器的参数就行测试
        @Test
        public void test09(){
            //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)
            String username = "a";
            Integer ageBegin = null;
            Integer ageEnd = 30;
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            if(StringUtils.isNotBlank(username)){
                //isNotBlank判断某个字符创是否不为空字符串、不为null、不为空白符
                queryWrapper.like("name", username);
            }
            if(ageBegin != null){
                queryWrapper.ge("age", ageBegin);
            }
            if(ageEnd != null){
                queryWrapper.le("age", ageEnd);
            }
            List<User> list = userMapper.selectList(queryWrapper);
            list.forEach(System.out::println);
        }

  • Idea 2 Manera simple de escribir: use el parámetro de condición

  • Si se cumple la condición del parámetro de condición, se ejecuta la condición en el constructor de condición

  • No hay problema con el esquema de implementación anterior, pero el código es más complicado.Podemos usar el método sobrecargado con el parámetro de condición para construir la condición de consulta y simplificar la escritura del código.

     //简单写法:使用condition参数
        @Test
        public void test10(){
            //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)
            String username = "a";
            Integer ageBegin = null;
            Integer ageEnd = 30;
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.like(StringUtils.isNotBlank(username),"name",username)
                    .ge(ageBegin!=null,"age",20)
                    .le(ageEnd!=null,"age",20);
            List<User> list = userMapper.selectList(queryWrapper);
          list.forEach(System.out::println);
        }

5.LambdaQueryWrapper

La función es equivalente a QueryWrapper y se proporciona la sintaxis de la expresión Lambda para evitar completar nombres de columna incorrectos. Haga coincidir automáticamente los nombres de los campos con los nombres de los atributos

 //LambdaQueryWrapper:提供了Lambda表达式的语法可以避免填错列名。通过属性名自动匹配字段名
    //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)
    @Test
    public void test11(){
        String username = "a";
        Integer ageBegin = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username),User::getName,username)
                .ge(ageBegin!=null,User::getAge,20) //User::getAge:通过属性名自动匹配字段名
                .le(ageEnd!=null,User::getAge,20);
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

6.Contenedor de actualización de Lambda

La función es equivalente a UpdateWrapper y se proporciona la sintaxis de la expresión Lambda para evitar completar nombres de columna incorrectos.

//LambdaUpdateWrapper:功能等同于UpdateWrapper,提供了Lambda表达式的语法可以避免填错列名。
//UPDATE t_user SET name=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
 @Test
public void test12(){
    //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.like(User::getName, "a")
        .and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail));
    updateWrapper.set(User::getName, "小黑").set(User::getEmail,"[email protected]");
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result:"+result);
}

Seis complementos de uso común

1. Complemento de paginación

MyBatis Plus tiene su propio complemento de paginación, y la función de paginación se puede realizar con una configuración simple

  • Importar dependencias de mybatis-plus

    <!--mybatis-plus启动器-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    ​
     <!-- 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.27</version>
    </dependency>

  • Agregar clase de configuraciónMyBatisPlusConfig

    @Configuration
    @MapperScan("com.atguigu.mybatisplus.mapper")
    public class MyBatisPlusConfig {
        //配置MybatisPlus的插件的  Interceptor:拦截器
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            //添加分页插件  DbType:数据库类型
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
    }
  • método de prueba de escritura

    @Test
    public void testPage(){
        //new Page()中的两个参数分别是当前页码,每页显示数量
        //SELECT id,name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
            Page<User> page = new Page<>(2,2);
            Page<User> userPage = userMapper.selectPage(page, null);
    ​
            System.out.println(userPage);
          List<User> users = page.getRecords();//分页后的数据
            users.forEach(System.out::println);
    ​
            System.out.println("总页数:"+userPage.getPages());
            System.out.println("总条数:"+userPage.getTotal());
            System.out.println("当前页:"+userPage.getCurrent());
            System.out.println("当前页显示条数:"+userPage.getSize());
            System.out.println("是否有下一页:"+userPage.hasNext());
            System.out.println("是否有上一页:"+userPage.hasPrevious());
    }

2. Paginación personalizada

La llamada anterior es el método con paginación proporcionado por MyBatis-Plus, entonces, ¿cómo implementamos la paginación en el método definido por nosotros mismos?

  • UserMapperdefinir un método en la interfaz

    /**
      * 根据年龄大于20的用户查询用户列表,分页显示 
      * @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位 
      * @param age 年龄 
      * @return 
      */
    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
  • UserMapper.xmlEscriba SQL para implementar este método en

    <select id="selectPageVo" resultType="User">
        select id,username as name,age,email from t_user where age > #{age}
    </select>
  • método de prueba de escritura

    @Test
    public void testPageVo(){
        Page<User> page = userMapper.selectPageVo(new Page<User>(1,2), 20);
        List<User> users = page.getRecords();
        users.forEach(System.out::println);
    }

    segunda forma de escribir

    //自定义分页 根据年龄大于20的用户查询用户列表,分页显示 
    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1,2);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age",20);
        userMapper.selectPage(page,queryWrapper);
        List<User> users = page.getRecords();
        users.forEach(System.out::println);
    }

3. Cerradura optimista

Función: cuando se va a actualizar un registro, se espera que este registro no haya sido actualizado por otros

Implementación de bloqueo optimista:

  • Al buscar registros, obtener la versión actual

  • Al actualizar, traer esta versión

  • Al realizar una actualización, ACTUALIZAR t_product SET nombre=?, precio=100+50, versión(nuevo valor después del cambio+1)=1 DONDE id=?Y versión(valor anterior)=0.

  • Satisfaga la condición, newVersion: oldVersion El valor anterior será +1 cada vez

  • Si la versión es incorrecta, la actualización fallará

3.1 Escenarios


  • Una mercancía tiene un precio de costo de 80 yuanes y un precio de venta de 100 yuanes. El jefe primero notificó a Xiao Li que debería aumentar el precio del producto en 50 yuanes. Xiao Li estaba jugando y se retrasó una hora. Exactamente una hora después, el jefe sintió que el precio del producto había aumentado a 150 yuanes, lo que era demasiado alto y podría afectar las ventas. También informe a Xiao Wang que reducirá el precio del producto en 30 yuanes.

  • En este momento, Xiao Li y Xiao Wang operan el sistema de fondo de productos básicos al mismo tiempo. Cuando Xiao Li operó, el sistema primero sacó el precio del producto de 100 yuanes; Xiao Wang también estaba operando, y el precio del producto extraído también fue de 100 yuanes. Xiao Li agregó 50 yuanes al precio y almacenó 100+50=150 yuanes en la base de datos; Xiao Wang redujo el producto en 30 yuanes y almacenó 100-30=70 yuanes en la base de datos. Sí, si no hay bloqueo, la operación de Xiao Li estará completamente cubierta por la de Xiao Wang.

  • Ahora el precio de la materia prima es de 70 yuanes, que es 10 yuanes más bajo que el precio de costo. Unos minutos más tarde, este producto vendió rápidamente más de 1,000 artículos y el jefe perdió más de 10,000.

3.2 Bloqueo optimista y bloqueo pesimista


  • En la historia anterior, si se trata de un candado optimista, Xiao Wang comprobará si el precio se ha modificado antes de guardar el precio. Si se ha modificado, se recuperará nuevamente el precio revisado, 150 yuanes, por lo que almacenará 120 yuanes en la base de datos.

  • Si es un bloqueo pesimista, después de que Xiao Li elimine los datos, Xiao Wang solo puede operar con el precio después de que Xiao Li termine la operación, y se garantizará que el precio final sea de 120 yuanes.

3.3 Simular conflictos de modificación


  • Agregar tabla de productos básicos a la base de datos

    CREATE TABLE t_product ( 
        id BIGINT(20) NOT NULL COMMENT '主键ID', 
        NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', 
        price INT(11) DEFAULT 0 COMMENT '价格', 
        VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号', 
        PRIMARY KEY (id) 
    );

  • agregar un dato

    INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人笔记本', 100);

  • añadir una clase de entidadProduct

    @Data
    public class Product {
        private Long id;
        private String name;
        private Integer price;
        private Integer version;
    }

  • Agregar una interfaz de mapeadorProductMapper

    public interface ProductMapper extends BaseMapper<Product> {}

  • Métodos de prueba

      
      //模拟修改冲突
        @Test
        public void testProduct01(){
            //1.小李获取商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productLi = productMapper.selectById(1);
            System.out.println("小李获取的商品价格为:" + productLi.getPrice());//100
    ​
            //2.小王获取商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productWang = productMapper.selectById(1);
            System.out.println("小王获取的商品价格为:" + productWang.getPrice());//100
    ​
            //3.小李修改商品价格+50
            productLi.setPrice(productLi.getPrice()+50);
            //UPDATE t_product SET name=?, price=100+50, version=? WHERE id=?
            productMapper.updateById(productLi);//100+50=150
    ​
            //4.小王修改商品价格-30
            productWang.setPrice(productWang.getPrice()-30);
            //UPDATE t_product SET name=?, price=100-30, version=? WHERE id=?
            productMapper.updateById(productWang);//100-30=70
    ​
            //5.老板查询商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productBoss = productMapper.selectById(1);
            System.out.println("老板获取的商品价格为:" + productBoss.getPrice());//70
        }

  • Resultados de la

3.4 El bloqueo optimista resuelve el problema


  • versionAgregar anotaciones a campos de clase de entidad@Version

    @Data
    public class Product {
        private Long id;
        private String name;
        private Integer price;
        @Version //标识乐观锁版本号字段
        private Integer version;
    }

  • Agregar configuración de complemento de bloqueo optimista

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

  • Ejecute el método de prueba nuevamente, prueba de bloqueo optimista

    Xiao Li pregunta sobre la información del producto:

    SELECCIONE id, nombre, precio, versión DESDE t_product DONDE id=?

    Xiao Wang pregunta sobre la información del producto:

    SELECCIONE id, nombre, precio, versión DESDE t_product DONDE id=?

    Xiao Li modifica el precio del producto y agrega automáticamente la versión+1

    ACTUALIZAR t_product SET nombre=?, precio=?, versión=? DONDE id=? Y versión =?

    Parámetros: cuaderno alienígena (cadena), 150 (entero), 1 (entero), 1 (largo), 0 (entero)

    Xiao Wang modifica el precio del producto. En este momento, la versión se ha actualizado. Si la condición no se cumple, la modificación falla.

    ACTUALIZAR t_product SET nombre=?, precio=?, versión=? DONDE id=? Y versión =?

    Parámetros: cuaderno alienígena (cadena), 70 (entero), 1 (entero), 1 (largo), 0 (entero)

    Al final, Xiao Wang no pudo modificar y el precio de la consulta: 150

    SELECCIONE id, nombre, precio, versión DESDE t_product DONDE id=?

  • //乐观锁测试
    @Test
    public void testProduct02(){
     //1.小李获取商品价格
     //SELECT id,name,price,version FROM t_product WHERE id=?
     Product productLi = productMapper.selectById(1);
     System.out.println("小李获取的商品价格为:" + productLi.getPrice());//100
    ​
     //2.小王获取商品价格
     //SELECT id,name,price,version FROM t_product WHERE id=?
     Product productWang = productMapper.selectById(1);
     System.out.println("小王获取的商品价格为:" + productWang.getPrice());//100
    ​
     //3.小李修改商品价格+50
     productLi.setPrice(productLi.getPrice()+50);//100+50=150
     //UPDATE t_product SET name=?, price=100+50, version=1 WHERE id=? AND version=0
     productMapper.updateById(productLi);//现在版本号已经变成1了
    ​
     //4.小王修改商品价格-30
     productWang.setPrice(productWang.getPrice()-30); //100-30=70
     //UPDATE t_product SET name=?, price=100-30, version=1 WHERE id=? AND version=0
     productMapper.updateById(productWang);//现在版本号已经变成1了,所以这里没有修改成功
    ​
     //5.老板查询商品价格
     //SELECT id,name,price,version FROM t_product WHERE id=?
     Product productBoss = productMapper.selectById(1);
     System.out.println("老板获取的商品价格为:" + productBoss.getPrice());//150
    }

  • Optimizar el proceso de ejecución

      //优化乐观锁测试
        @Test
        public void testProduct03(){
            //1.小李获取商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productLi = productMapper.selectById(1);
            System.out.println("小李获取的商品价格为:" + productLi.getPrice());//100
    ​
            //2.小王获取商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productWang = productMapper.selectById(1);
            System.out.println("小王获取的商品价格为:" + productWang.getPrice());//100
    ​
            //3.小李修改商品价格+50
            productLi.setPrice(productLi.getPrice()+50);//100+50=150
            //UPDATE t_product SET name=?, price=100+50, version=1 WHERE id=? AND version=0
            productMapper.updateById(productLi);//现在版本号已经变成1了
    ​
            //4.小王修改商品价格-30
            productWang.setPrice(productWang.getPrice()-30); //100-30=70
            //UPDATE t_product SET name=?, price=100-30, version=1 WHERE id=? AND version=0
            int result = productMapper.updateById(productWang);//现在版本号已经变成1了,所以这里没有修改成功
            if(result == 0){
                //操作失败,重试
                //重新查询一次,这是小李修改玩的数据
                Product productNew = productMapper.selectById(1);
                //再次更新,现在价格是150-30
                productNew.setPrice(productNew.getPrice()-30);
                //再次修改
              productMapper.updateById(productNew);
            }
    ​
            //5.老板查询商品价格
            //SELECT id,name,price,version FROM t_product WHERE id=?
            Product productBoss = productMapper.selectById(1);
            System.out.println("老板获取的商品价格为:" + productBoss.getPrice());//120
        }

Siete, enumeración general

Algunos valores de campo en la tabla son fijos, como el género (masculino o femenino), en este momento podemos usar la enumeración general de MyBatis-Plus para lograr

  • Agregar campo a la tabla de la base de datossex

  • Crear un tipo de enumeración genérico

    @Getter
    public enum SexEnum {
        MALE(1, "男"),
        FEMALE(2, "女");
    ​
        @EnumValue //将注解所标识的属性的值存储到数据库中
        private int sex;
        private String sexName;
    ​
        SexEnum(Integer sex, String sexName) {
            this.sex = sex;
            this.sexName = sexName;
        }
    }

  • Agregar atributo sexo a la clase de entidad de usuario

    public class User {
        private Long id;
        @TableField("username")
        private String name;
        private Integer age;
        private String email;
    ​
        @TableLogic
        private int isDeleted;  //逻辑删除
    ​
        private SexEnum sex;
    }

  • Configurar la enumeración genérica de escaneo

    #MyBatis-Plus相关配置
    mybatis-plus:
      #指定mapper文件所在的地址
      mapper-locations: classpath:mapper/*.xml
      configuration:
        #配置日志
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      global-config:
        banner: off
        db-config:
          #配置mp的主键策略为自增
          id-type: auto
          # 设置实体类所对应的表的统一前缀
          table-prefix: t_
      #配置类型别名所对应的包
      type-aliases-package: com.atguigu.mybatisplus.pojo
      # 扫描通用枚举的包
      type-enums-package: com.atguigu.mybatisplus.enums

  • Ejecutar el método de prueba

    @Test
    public void test(){
        User user = new User();
        user.setName("admin");
        user.setAge(33);
        user.setSex(SexEnum.MALE);
        int result = userMapper.insert(user);
        System.out.println("result:"+result);
    }

8. Generador de código

1. Introducir dependencias

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>//代码生成器的核心依赖
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>//freemarker引擎模板依赖
    <version>2.3.31</version>
</dependency>

2. Generación rápida

public class FastAutoGeneratorTest {
​
  public static void main(String[] args) {
    FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?
         characterEncoding=utf-8&userSSL=false", "root", "123456")
    .globalConfig(builder -> {
        builder.author("atguigu") // 设置作者
         //.enableSwagger() // 开启 swagger 模式
        .fileOverride() // 覆盖已生成文件
        .outputDir("D://mybatis_plus"); // 指定输出目录
     })
    .packageConfig(builder -> {
        builder.parent("com.atguigu") // 设置父包名
        .moduleName("mybatisplus") // 设置父包模块名
         // 设置mapperXml映射文件生成路径
        .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus"));
    })
    .strategyConfig(builder -> {
        builder.addInclude("t_user") // 设置需要生成的表名
        .addTablePrefix("t_", "c_"); // 设置过滤表前缀
    })
    .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    .execute();
    }
}

Nueve, múltiples fuentes de datos

Aplicable a una variedad de escenarios: multibiblioteca pura, separación de lectura y escritura, un maestro y varios esclavos, modo mixto, etc.

Descripción del escenario:

Creamos dos bibliotecas, respectivamente: mybatis_plus(la biblioteca anterior no se mueve) y (nueva), y movemos las tablas mybatis_plus_1de la biblioteca mybatis_plus a la biblioteca mybatis_plus_1, para que cada biblioteca tenga una tabla, y se obtengan los datos de usuario y de producto a través de un caso de prueba product, si se obtiene, significa que la simulación multibiblioteca es exitosa

1. Crear base de datos y tabla

  • Crear base de datos mybatis_plus_1y tabla `producto

    CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
    use `mybatis_plus_1`; 
    CREATE TABLE product ( 
        id BIGINT(20) NOT NULL COMMENT '主键ID', 
        name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', 
        price INT(11) DEFAULT 0 COMMENT '价格', 
        version INT(11) DEFAULT 0 COMMENT '乐观锁版本号', 
        PRIMARY KEY (id) 
    );
  • Agregar datos de prueba

    INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
  • mesa desplegable mybatis_plusen la bibliotecaproduct

    use mybatis_plus; 
    DROP TABLE IF EXISTS product;

2. Los nuevos proyectos introducen dependencias

Cree un nuevo proyecto Spring Boot usted mismo y seleccione el controlador MySQL y las dependencias de Lombok

Introducir dependencias en múltiples fuentes de datos

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>

3. Escribir archivos de configuración

spring:
  # 配置数据源信息
  datasource:
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: master
      # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
       # 配置多数据源信息
      datasource:
      #主数据源
        master:
          url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 123456
        #从数据源
        slave_1:
          url: jdbc:mysql://localhost:3306/mybatis_plus_1?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 123456

4. Crear clase de entidad

  • Cree una nueva Userclase de entidad (si el nombre de la tabla de la base de datos tiene un prefijo t_, recuerde configurarlo)

    @Data
    @TableName("t_user")//指定表
    public class User {
    ​
        private Long id;
    ​
        private String name;
    ​
        private Integer age;
    ​
        private Integer sex;
    ​
        private String email;
    ​
        private Integer isDeleted;
    }

  • Crear una nueva clase de entidadProduct

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Product {
    ​
        private Long id;
    ​
        private String name;
    ​
        private Integer price;
    ​
        private Integer version;
    }

5. Crear Mapeador y Servicio

  • nueva interfazUserMapper

    @Repository
    public interface UserMapper extends BaseMapper<User> {}
  • nueva interfazProductMapper

    @Repository
    public interface ProductMapper extends BaseMapper<Product> {}
  • Cree una nueva interfaz de servicio UserServicepara especificar el origen de datos para la operación

    public interface UserService extends IService<User> {}
  • Cree una nueva interfaz de servicio ProductServicepara especificar el origen de datos para la operación

    public interface ProductService extends IService<Product> {}
  • UserServiceClase de implementación creada

    @Service
    @DS("master")//多数据源操作,指定要操作的数据源,master指定的是mybatis_plus数据库里面有t_user表,不写注解使用默认数据源
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    }

    ProductServiceClase de implementación creada

    @Service
    @DS("slave_1")//多数据源操作,指定要操作的数据源,slave_1指定的是mybatis_plus1数据库里面有product表,不写注解使用默认数据源
    public class ProductServiceImpl extends ServiceImpl<ProductMapper,Product> implements ProductService{
    ​
    }

6. Escriba el método de prueba

Recuerde agregar anotaciones a la clase de inicio@MapperScan()

class TestDatasourceApplicationTests {
    @Resource
    UserService userService;
​
    @Resource
    ProductService productService;
​
    @Test
    void contextLoads() {
        User user = userService.getById(1L);
        Product product = productService.getById(1L);
        System.out.println("User = " + user);
        System.out.println("Product = " + product);
    }
​
}

10. Complemento MyBatisX

MyBatis-Plus nos proporciona potentes plantillas de mapas y servicios, que pueden mejorar en gran medida la eficiencia del desarrollo.

Pero en el proceso de desarrollo real, MyBatis-Plus no puede resolver todos los problemas por nosotros, como algunos SQL complejos, consultas conjuntas de tablas múltiples, necesitamos escribir el código y la declaración SQL por nosotros mismos, ¿cómo podemos resolver este problema rápidamente? vez, puedes usar el complemento MyBatisX.

MyBatisX es un complemento de desarrollo rápido basado en IDEA, nacido para la eficiencia.

1. Instala el complemento MyBatisX

Abra IDEA, Archivo-> Configuración-> Complementos-> MyBatisX, busque MyBatisX en la barra de búsqueda e instálelo.

2. Genera código rápidamente

  • Cree un nuevo proyecto Spring Boot para introducir dependencias (recuerde verificar los controladores lombok y mysql al crear el proyecto)

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    ​
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.5.0</version>
    </dependency>

  • Configurar la información de la fuente de datos

    spring:
      #配置数据库
      datasource:
        # 配置连接数据库信息
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
        username: root
        password: 123456

  • Establecer un enlace con la base de datos en IDEA

  • Complete la información de la base de datos y guarde

  • ?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false 

  • Encuentre la tabla que necesitamos generar y haga clic derecho

  • Siguiente paso después de completar la información

  • continúa completando la información

  • Ya terminaste (muy fácil de usar yyds)

3. Genera CRUD rápidamente

MyBaitsX puede ayudarnos a generar rápidamente la instrucción sql correspondiente de acuerdo con el nombre del método que ingresamos en la interfaz de Mapper

public interface UserMapper extends BaseMapper<User> {
​
    //mybatisX快速生成CRUD 方法名都是见名实意
    //增加
    int insertSelective(User user);
​
    //删除 通过id和年龄和姓名删除
    int deleteByIdAndAgeAndName(@Param("id") Long id, @Param("age") Integer age, @Param("name") String name);
​
    //修改 通过id修改年龄跟性别
    int updateAgeAndSexById(@Param("age") Integer age, @Param("sex") Integer sex, @Param("id") Long id);
​
    //查询 通过开始年龄和结束年龄查询年龄和性别
    List<User> selectAgeAndSexByAgeBetween(@Param("beginAge") Integer beginAge, @Param("endAge") Integer endAge);
​
    //查询全部
    List<User> selectAll();
​
    //通过年龄降序查询全部
    List<User> selectAllOrderByAgeDesc();
}
​

prueba

@SpringBootTest
class Boot04MybatisxDemoApplicationTests {
​
    @Autowired
    UserMapper userMapper;
​
    @Test
    void contextLoads() {
        
        List<User> users = userMapper.selectAll();
        System.out.println(users);
        
        List<User> users1 = userMapper.selectAgeAndSexByAgeBetween(10, 20);
        System.out.println(users1);
    }
​
}

Supongo que te gusta

Origin blog.csdn.net/m0_65992672/article/details/130565444
Recomendado
Clasificación