Springboot simplesmente usa mybatisplus

contente

o que é mybatisplus

característica

Estrutura de diretórios

Primeiro importe as dependências:

Crie o banco de dados:

Conecte-se ao banco de dados

Criar classe de entidade: (usando o plugin lombok)

interface do mapeador

Então precisamos escanear todas as interfaces em nosso pacote mapeador na classe de inicialização principal

então teste na classe de teste

operação de consulta

 operação de atualização

resumo:

Estratégia de geração de chave primária

preenchimento automático

bloqueio otimista

Consulta de paginação

Lápide

Construtor condicional


o que é mybatisplus

mybatisplus é uma  ferramenta de aprimoramento do MyBatis (abre uma nova janela) , que apenas aprimora e não muda com base no MyBatis. Nasceu para simplificar o desenvolvimento e melhorar a eficiência.

característica

  • Não invasivo : apenas faça melhorias sem alterar, a introdução não afetará os projetos existentes, suave como seda
  • Baixa perda : O CURD básico é injetado automaticamente na inicialização, o desempenho é basicamente sem perdas e a operação direta orientada a objetos
  • Operações CRUD poderosas : mapeador geral e serviço geral integrados, a maioria das operações CRUD em uma única tabela pode ser realizada com apenas uma pequena quantidade de configuração e construtores condicionais mais poderosos para atender a várias necessidades de uso
  • Suporte à invocação de formulários Lambda : por meio de expressões Lambda, você pode escrever facilmente várias condições de consulta e não precisa se preocupar em escrever campos errados.
  • Suporta geração automática de chave primária : suporta até 4 estratégias de chave primária (incluindo um gerador de ID exclusivo distribuído - Sequência), que pode ser configurado livremente para resolver perfeitamente o problema da chave primária
  • Suporte ao modo ActiveRecord : Suporte a chamada de formulário ActiveRecord, a classe de entidade pode executar operações CRUD poderosas apenas herdando a classe Model
  • Suporte a operações gerais globais personalizadas : suporte a injeção de método geral global (Escreva uma vez, use em qualquer lugar)
  • Gerador de código integrado : Use código ou plug-in Maven para gerar rapidamente Mapper, Model, Service, código de camada de controlador, mecanismo de modelo de suporte e mais configurações personalizadas esperando por você para usar
  • Plug-in de paginação integrado: Com base na paginação física do MyBatis, os desenvolvedores não precisam se preocupar com operações específicas.
  • O plugin de paginação suporta vários bancos de dados : MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer e outros bancos de dados
  • Plug-in de análise de desempenho integrado: pode gerar instruções Sql e seu tempo de execução. Recomenda-se habilitar esta função durante o desenvolvimento e teste, o que pode identificar rapidamente consultas lentas
  • Plug-in de interceptação global integrado : fornece análise inteligente e bloqueio de operações de exclusão e atualização em toda a tabela e também pode personalizar regras de interceptação para evitar operações incorretas

Estrutura de diretórios

Primeiro importe as dependências:


        <!-- 数据库驱动 --> <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
       <version>5.1.47</version>
       </dependency>
        <!-- lombok --> <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
              </dependency>

        <!-- mybatis-plus --> <!-- mybatis-plus 是自己开发,并非官方的! -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>

Crie o banco de dados:

create database mybatisplus;
use mybatisplus;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL COMMENT '主键ID',
  `name` varchar(30) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL COMMENT '姓名',
  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) CHARACTER SET gbk COLLATE gbk_chinese_ci NULL DEFAULT NULL COMMENT '邮箱',
  `version` int(25) NULL DEFAULT 1,
  `deleted` int(10) NULL DEFAULT 1,
  `create_time` datetime NULL DEFAULT NULL,
  `update_time` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = gbk COLLATE = gbk_chinese_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'test232', 18, '[email protected]', 4, 0, NULL, '2021-07-26 23:06:43');
INSERT INTO `user` VALUES (2, 'Jack', 20, '[email protected]', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (3, 'Tom', 28, '[email protected]', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (4, 'Sandy', 21, '[email protected]', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (5, 'Billie', 24, '[email protected]', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (55, '小h黑3', 29, '@12910000', 1, 0, NULL, '2021-07-26 17:18:21');
INSERT INTO `user` VALUES (1419574597568741377, '小明2', 10, '@1291759046', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (1419574597568741378, '小明3', 10, '@1291759046', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (1419578836433018881, '小明3', 10, '@1291759046', 1, 0, NULL, NULL);
INSERT INTO `user` VALUES (1419582624418045954, '小明5', 10, '@1291759046', 1, 1, NULL, NULL);



-- 真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified

Conecte-se ao banco de dados

# mysql 5 驱动不同 com.mysql.jdbc.Driver
# mysql 8 驱动不同com.mysql.cj.jdbc.Driver、需要增加时区的配置 serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus? useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

Criar classe de entidade: (usando o plugin lombok)

package com.chen.pojo;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //主键注解
    //对应数据库中的主键(uuid,自增id,雪花算法,redis,zookeeper)
//    AUTO	数据库ID自增
//    NONE	无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
//    INPUT	insert前自行set主键值
//    ASSIGN_ID	分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
//    ASSIGN_UUID	分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    //字段注解(非主键)
    // 字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;
    @Version
    //乐观锁Version注解
    private Integer version;

    @TableLogic
    //逻辑删除
    private Integer deleted;
}

interface do mapeador

package com.chen.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chen.pojo.User;
import org.springframework.stereotype.Repository;

// 在对应的Mapper上面继承基本的类 BaseMapper
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {

// 所有的CRUD操作都已经编写完成了
// 不需要像以前的配置一大堆文件了!

}

Então precisamos escanear todas as interfaces em nosso pacote mapeador na classe de inicialização principal

@MapperScan("com.chen.mapper")

então teste na classe de teste

operação de consulta

  @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        // 参数是一个 Wrapper ,条件构造器,这里我们先不用 null
        // 查询全部用户
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);

    }

resultado de saída

   //测试查询
    @Test
    public void testQuery(){
        User user=userMapper.selectById(1L);
        System.out.println(user);
    }

    // 测试批量查询!
     @Test
    public void testSelectByBatchId(){
     List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
     users.forEach(System.out::println);
    }
     // 按条件查询之一使用map操作
    @Test
    public void testSelectByBatchIds(){
        HashMap<String, Object> map = new HashMap<>();
        // 自定义要查询
        map.put("name","test222");
        map.put("age",18);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

operação de inserção

 //测试插入
    @Test
    public  void insertTest(){
        User user=new User();
        user.setAge(10);
        user.setEmail("@1291759046");
        user.setName("小明8");
        //user.setId(55l);
        userMapper.insert(user);
    }

 operação de atualização

 //测试更新
    @Test
    public void testUpdate(){
        User user=new User();
        user.setId(55L);
        user.setAge(29);
        user.setEmail("@12910000");
        user.setName("小h黑555");
        userMapper.updateById(user);

    }

Aqui está a atualização com base no id

resumo:

Através das etapas simples acima, percebemos a função CRUD da tabela User e nem precisamos escrever um arquivo XML!

A partir das etapas acima, podemos ver que a integração MyBatis-Plusé muito simples, precisamos apenas introduzir o projeto inicial e configurar o caminho de varredura do mapeador.

Mas o poder do MyBatis-Plus é muito mais do que essas funções. Quer saber mais sobre as poderosas funções do MyBatis-Plus? Então continue olhando para baixo

Estratégia de geração de chave primária

Observe o teste de inserção acima, você pode descobrir que o id da chave primária não está inserido, mas um id exclusivo é gerado, isso ocorre porque o id de alocação está definido

  @TableId(type = IdType.ASSIGN_ID)
    private Long id;

Se o id for definido como @TableId(type = IdType.AUTO)
    private Long id;

No banco de dados, defina o campo ID do banco de dados para o tipo de incremento automático

preenchimento automático

Tempo de criação, tempo de modificação! Essas operações são todas feitas automaticamente, não queremos atualizar manualmente!
nível de código
Atributos de campo de classe de entidade precisam adicionar anotações
 //字段注解(非主键)
    // 字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;
Escreva um processador para lidar com esta anotação!
Crie  a classe MyMetaObjectHandler
package com.chen.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

@Slf4j
@Component
// 一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill.....");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
        this.setFieldValByName("createTime",new Date(),metaObject);
   //     this.setFieldValByName("updateTime", new Date(), metaObject);
//        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
//        // 或者
//        this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
//        // 或者
//        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
    }

    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill.....");
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

Teste adicionando e alterando dados, o tempo é gerado automaticamente

bloqueio otimista

Quando um registro deve ser atualizado, espera-se que o registro não tenha sido atualizado por outros
.

  • Ao buscar um registro, obtenha a versão atual
  • Ao atualizar, traga esta versão
  • Ao realizar uma atualização, defina version = newVersion onde version = oldVersion
  • Se a versão estiver errada, a atualização falha
Este tipo de versão desde que o segmento foi criado no banco de dados
Classe de entidade mais campos correspondentes
   @Version
    //乐观锁Version注解
    private Integer version;

Registrar componentes

Criar classe de configuração classe MyBatisPlusConfig


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.chen.pojo.User;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 扫描我们的 mapper 文件夹
@MapperScan("com.chen.pojo")
@EnableTransactionManagement
@Configuration
// 配置类
public class MyBatisPlusConfig
{
    // 注册乐观锁插件

    /**
     * 旧版
     */
//    @Bean
//    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
//        return new OptimisticLockerInterceptor();
//    }

    /**
     * 新版
     */
    // 注册乐观锁插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }




}

realizar testes

 //测试乐观锁成功·
    @Test
    public void testOptimisticloker(){
        //1.查询用户信息
        User user=userMapper.selectById(1);
        //2.修改用户信息
        user.setName("哈哈哈哈");
        user.setEmail("[email protected]");
        //执行更新操作
        userMapper.updateById(user);
    }
 // 测试乐观锁失败!多线程下
    @Test
    public void testOptimisticLocker2(){
        // 线程 1
        User user = userMapper.selectById(1L);
        user.setName("test1111111");
        user.setEmail("[email protected]");
        // 模拟另外一个线程执行了插队操作
        User user2 = userMapper.selectById(1L);
        user2.setName("test000000");
        user2.setEmail("[email protected]");
        userMapper.updateById(user2);
        // 自旋锁来多次尝试提交!
        userMapper.updateById(user);
        // 如果没有乐观锁就会覆盖插队线程的值!
        }

Aqui será encontrado que a atualização do usuário de user1 falha, a atualização do usuário de user2 é bem-sucedida e o valor da versão no banco de dados é aumentado em um, porque a atualização do usuário de user1 falha devido à adição de um, que é um bloqueio otimista

Consulta de paginação

1 , o limite original para paginação
2. Plugin de terceiros do pageHelper
3. Na verdade, o MP tem um plug-in de paginação embutido !
Configurar o componente interceptor

Adicionar em MyBatisPlusConfig

package com.chen.config;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.chen.pojo.User;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 扫描我们的 mapper 文件夹
@MapperScan("com.chen.pojo")
@EnableTransactionManagement
@Configuration
// 配置类
public class MyBatisPlusConfig
{
    


    //分页插件
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor2() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

teste

 // 测试分页查询
    @Test
    public void testPage(){
        // 参数一:当前页
        // 参数二:页面大小
        // 使用了分页插件之后,所有的分页操作也变得简单的!
        Page<User> page = new Page<>(2,5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }

Lápide

  • Tombstone é um esquema para facilitar a recuperação de dados e proteger o valor dos próprios dados, etc., mas na verdade é a exclusão.
  • Se você precisar pesquisar com frequência, não use a lápide, mas represente-a como um estado.
exclusão física
: Remover diretamente do banco de dados
Lápide
: Não é removido do banco de dados, mas é invalidado por uma variável! deletado = 0 => deletado = 1
Os administradores podem visualizar os registros excluídos! Evite a perda de dados, semelhante à Lixeira!
Adicione um campo excluído à tabela de dados , onde o banco de dados foi adicionado
  @TableLogic
    //逻辑删除
    private Integer deleted;
Coloque application.yml
# 配置逻辑删除
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

teste:

// 测试删除
    @Test
    public void testDeleteById(){
        userMapper.deleteById(1420632853468803073L);
    }
    // 通过id批量删除
    @Test
    public void testDeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(1240620674645544961L,1240620674645544962L));
    }
    // 通过map删除
    @Test
    public void testDeleteMap() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "小明6");
        userMapper.deleteByMap(map);
    }

Verifica-se que a exclusão lógica é bem-sucedida, os dados não são realmente excluídos, mas o estado excluído é alterado

Construtor condicional

  1. a embalagem é pesada
  2. Transmitir wrappers pode ser análogo ao recebimento de valores com mapa para seu controlador (desenvolvendo momentaneamente, mantendo crematório)
  3. A postura correta de chamada RPC é escrever um DTO para transmissão, e o chamador executa a operação correspondente de acordo com o DTO
  4. Nós nos recusamos a aceitar qualquer problema ou mesmo pr relacionado ao relatório de erros do wrapper de transporte RPC
Podemos usá-lo em vez de escrever algum sql complexo!
teste:
Crie a classe WrapperTest
package com.chen;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chen.mapper.UserMapper;
import com.chen.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

@SpringBootTest
public class WrapperTest {

    @Autowired
    private UserMapper userMapper;
    @Test
   public void contextLoads() {
        // 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        userMapper.selectList(wrapper).forEach(System.out::println);

        // 和我们刚才学习 的map对比一下
        }

    @Test
   public void test2(){
        // 查询名字
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","小h黑3");
        User user = userMapper.selectOne(wrapper);
        // 查询一个数据,出现多个结果使用List 或者 Map
        System.out.println(user);
        //
        }

    @Test void test3(){
        // 查询年龄在 20 ~ 30 岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,30);
        // 区间
        Integer count = userMapper.selectCount(wrapper);
       userMapper.selectList(wrapper).forEach(System.out::println);
       // List<User> list= userMapper.selectList(wrapper);
      //  list.forEach(System.out::println);
        // 查询结果数
        System.out.println(count);
        }


    // 模糊查询
    @Test void test4(){
        // 查询年龄在 20 ~ 30 岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 左和右 t%
        wrapper .notLike("name","j") .likeRight("email","t");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

    // 模糊查询
    @Test void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // id 在子查询中查出来
        wrapper.inSql("id","select id from user where id<3");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }

    //测试六
    @Test void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 通过id进行排序
       // wrapper.orderByAsc("id");//升序
        wrapper.orderByDesc("id");//降序
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    //测试7
    @Test void test7(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",24,29);
        User user = new User();
        user.setAge(30);
        int n=userMapper.update(user,wrapper);



    }


}

Acho que você gosta

Origin blog.csdn.net/qq_44716544/article/details/119192652
Recomendado
Clasificación