Índice
springboot integra arquivos de configuração mybatisplus
Edite a interface do mapeador após definir a classe de entidade Usuário
A diferença entre @Mapper e @MapperScan("nome do pacote")
Excluir por mapa como condição
Consultar usuários com base em vários IDs
Consultar usuários com base na coleção de mapas como condição
Consultar o número total de registros
Use o construtor condicional para implementar operações de consulta
Consulte a coleção de campos de chave primária de acordo com o construtor
Consulte vários usuários de acordo com o construtor de condição
Consultar e classificar por caractere de escape
O construtor condicional implementa a operação de exclusão
Implementando operações de modificação usando construtores condicionais
Use updateWrapper para implementar a função de modificação
Classe de configuração de configuração (necessária)
Função de paginação personalizada
Adicione uma anotação de versão à classe de entidade que precisa ser alterada
Adicionar plugin de bloqueio otimista
Função de preenchimento automático de MP
Adicionar classe de configuração
Adicionar anotações a classes de entidades
MeuBatisPlus
Significado: mybatis-plus é uma ferramenta de aprimoramento para mybatis. Com base no mybatis, apenas melhorias são feitas sem alterações. Ele nasceu para simplificar o desenvolvimento e melhorar a eficiência
Nota: Podemos integrar diretamente o mybatisplus com base no mybatis, o que não afetará as funções do mybatis, e também podemos usar as funções fornecidas por ele.
Recursos do MP
- Apenas melhorias e nenhuma alteração são feitas no mybatis, e a introdução do mesmo não afetará os projetos existentes
- Necessita apenas de uma configuração simples para executar rapidamente operações CRUD de tabela única, economizando muito tempo
- Geração de código, paginação automática, exclusão lógica, funções de preenchimento automático, etc. estão disponíveis
Estrutura do quadro MP
entender:
- MP é composto por MP starter, parte de anotação, parte de extensão, parte central e parte de geração de código; esses conteúdos juntos suportam o processo de MP para realizar a função
- Função de implementação MP: primeiro, verifique a classe de entidade e, em seguida, extraia os atributos na classe de instância por meio da tecnologia de reflexão após a digitalização e analise o relacionamento entre a tabela e a classe de entidade após a extração; e os atributos na classe de entidade extraídos por meio de reflexão e O relacionamento entre nossos campos atuais; em seguida, gere a instrução sql correspondente de acordo com o método que estamos chamando no momento e, em seguida, injete a instrução sql de adição, exclusão, modificação e consulta no contêiner mybatis para atingir a função final
Preparação para uso de MP
dependências de importação
<dependencies>
<!--springboot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--springboot测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--MP启动器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动包--><!--测试功能的启动器-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
springboot integra arquivos de configuração mybatisplus
spring:
#设置数据源信息
datasource:
#配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT%2B8
username: root
password: root
mybatis-plus:
configuration:
#MP提供了日志功能
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#驼峰映射(默认就是开启的)
map-underscore-to-camel-case: true
#设置MP的全局配置
global-config:
db-config:
#这样设置的话,那么实体类所有的表都会加上t_前缀
table-prefix: t_
#设置统一主键生成策略
id-type: auto
#映射文件路径
mapper-locations: classpath:/mapper/UserMapper.xml
#配置类型别名所对应的包
type-aliases-package: cn.tedu.mybatisplus.pojo
#扫描通用枚举的包
type-enums-package: cn.tedu.mybatisplus.enums
Edite a interface do mapeador após definir a classe de entidade Usuário
//使用MP提供的通用mapper——BaseMapper
//BaseMapper里的泛型表示实体类的类型
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Perceber:
- O MP encapsula muitos métodos CRUD comumente usados, e os usuários só precisam herdar a interface de negócios pública BaseMapper quando necessário, melhorando assim a eficiência
- Os genéricos devem ser adicionados à interface BaseMapper, pois ela precisa obter a anotação especificada (e obter o valor da anotação), nome da tabela e seus atributos de acordo com o objeto genérico
A diferença entre @Mapper e @MapperScan("nome do pacote")
- @MapperScan("nome do pacote"): verifica a interface do mapeador no pacote especificado e entrega a classe proxy da interface ao contêiner Spring para armazenamento
- @Mapper: Entregue a classe proxy da interface para o contêiner Spring para armazenamento
- @Mapper é usado na interface especificada, @MapperScan("o nome do pacote da interface correspondente") é usado na classe de inicialização ou arquivo de configuração
Operação básica do MP
Nota: injete userMapper antes de usar
Adicionar operação
User user = new User();
user.setName("lili").setAge(23).setEmail("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
//mybatis-plus会自动获取id
System.out.println(user.getId());
operação de exclusão
excluir usuário por id
int i = userMapper.deleteById(7);
System.out.println(i);
Excluir por mapa como condição
Map<String,Object> map=new HashMap<>();
map.put("name", "张三");
map.put("age", 23);
//删除name为张三,age为23的人
int i = userMapper.deleteByMap(map);
System.out.println(i);
Excluir por ID múltiplo
List<Long> list = Arrays.asList(1L, 2L, 3L);
int i = userMapper.deleteBatchIds(list);
System.out.println(i);
atualizar usuário
Atualização de usuário por id
User user = new User();
user.setId(3L).setName("lan").setEmail("[email protected]");
//根据id修改元素
int i = userMapper.updateById(user);
System.out.println(i);
Consultar usuários
Consultar usuários por ID
User user = userMapper.selectById(1L);
System.out.println(user);
Consultar usuários com base em vários IDs
List<Long> list = Arrays.asList(1L, 2L, 3L);
List<User> users = userMapper.selectBatchIds(list);
users.forEach(System.out::println);
Consultar usuários com base na coleção de mapas como condição
HashMap<String, Object> map = new HashMap<>();
map.put("name", "lan");
map.put("age", 28);
List<User> users = userMapper.selectByMap(map);
//list会直接打印对象数组
System.out.println(users);
Interface de serviço comum
Descrição: o General Service encapsula a interface IService e encapsula ainda mais o CRUD usando get query single line, remove delete, list query collection, page pagination e outros métodos de nomenclatura de prefixo para distinguir a camada Mapper e evitar confusão
//service接口
public interface UserService extends IService<User> {
}
//service实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
Perceber:
- ServiceImpl<UserMapper, User> implementa a interface IService<User>
- UserService deve ser injetado primeiro ao usar
algumas operações
Consultar o número total de registros
//查询总记录数
long count = userService.count();
System.out.println(count);
Adicione dados em lotes
ArrayList<User> list = new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
User user = new User();
user.setName("cjc"+i).setAge(10+i);
list.add(user);
}
//批量添加数据
boolean b = userService.saveBatch(list);
//操作成功或失败
System.out.println(b);
Anotações comuns para MP
//设置实体类所对应的表名,若对象与表名一致,则表名中()可以省略
@TableName("t_user")
public class User {
//将当前属性对应的字段指定为主键(将该属性与数据库中的id字段进行映射),并通过雪花算法生成主键id
//type标识主键的生成策略为自动递增,要求数据库的主键为自增策略(默认为雪花算法——IdType.ASSIGN.ID)
@TableId(value = "id")
private Long id;
//将该注解标识的属性与数据库中的name字段一一映射,若属性名与字段名相同,则注解可省略
@TableField(value = "name")
private String name;
private Integer age;
private String email;
//逻辑删除0标识未删除,1标识已删除
//被逻辑删除的数据用户查不到,但是可以在数据库中看到,只是该属性变为1;(为修改操作)
@TableLogic
private Integer isDeleted;
}
Nota: A anotação @TableField(exit=false) é geralmente usada no atributo injetado, e o atributo atual do nome da tabela identificado por esta anotação não participa da operação do MP
algoritmo de floco de neve
prefácio
Contexto: São necessárias soluções adequadas para lidar com o crescimento da escala de dados, a fim de fazer face à crescente pressão de acesso e ao volume de dados
Métodos de expansão de tabelas de banco de dados: subbanco de dados de negócios, replicação mestre-escravo, subtabela de banco de dados
Duas formas de divisão de tabelas de banco de dados
- mesa vertical
- tabela de nível
mesa vertical
Coloque dados importantes em uma tabela e separe aqueles que não são usados em consultas de negócios em outra tabela para melhorar determinado desempenho
tabela de nível
Incremento automático de chave primária: por exemplo, divida a tabela de acordo com o intervalo (1-9999 é colocado na tabela 1 e 10000-20000 é colocado na tabela 2)
Módulo: chave primária% número de bancos de dados e colocar o mesmo restante em uma tabela
Algoritmo de floco de neve:
O Algoritmo Snowflake é um algoritmo de geração de chave primária distribuída pelo Twitter, que garante a não repetição das chaves primárias de tabelas diferentes e a ordenação das chaves primárias da mesma tabela
idéia principal:
- O comprimento é de 64 bits
- O primeiro é o bit de sinal, identificação de 1 bit, porque o tipo básico de long é assinado em java, o bit mais alto é o bit de sinal, o número positivo é 0 e o número negativo é 1, então id é geralmente um número positivo, o bit mais alto é 0
- 4 bits é o carimbo de data e hora (nível ms), que armazena a diferença do carimbo de data e hora (carimbo de data e hora atual - carimbo de data e hora de início), e o resultado é cerca de 69,73 anos
- 10 bits como o ID da máquina (5 bits é o data center, 5 bits é o ID da máquina, que pode ser implantado em 1.024 nós)
- 12 bits como o número de série em ms (o que significa que cada nó pode gerar 4.096 ids por milissegundo)
Vantagens: classificação geral de acordo com o incremento de tempo e não haverá colisão de ID em todo o sistema distribuído
construtor condicional
Função: Encapsular a condição atual
estrutura de herança
AbstractWrapper: Usado para encapsulamento de consulta condicional, onde as condições para gerar sql
- QueryWrapper: encapsulamento de condição de consulta
- UpdateWrapper: Atualizar empacotamento condicional
- AbstractLambdaWrapper: use sintaxe lambda
ResumoLambdaWrapper
- LambdaQueryWrapper: Query Wrapper para uso de sintaxe lambda
- LambdaUpdateWrapper: Wrapper do pacote de atualização lambda
Use o construtor condicional para implementar operações de consulta
consultar todos os usuários
//通过条件构造器查询一个list集合,若没有条件则可以设置null(相当于查询所有)
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
Consulte a coleção de campos de chave primária de acordo com o construtor
//查询name为lei的主键字段
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "lei");
List<Object> list = userMapper.selectObjs(queryWrapper);
System.out.println(list);
Consulte vários usuários de acordo com o construtor de condição
//查询用户名包含a,年龄在20-30之间,邮箱信息不为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//queryWrapper可以实现链式加载
queryWrapper.like("name", "a").between("age", 20, 30).isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
//对象形式
User user = new User();
user.setAge(28);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
//user内的属性最终会以and形式拼接
Sobre consulta difusa
- como: Indica que há% em ambos os lados de um
- likeleft: Indica que há % à esquerda de um
- likeright: Indica que existe uma % à direita de um
em consulta
//in查询,查询id为1,2,3的数据
Integer[] ids={1,2,3};
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id",ids);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
Consultar e classificar por caractere de escape
//查询id>2的用户,按照年龄降序排序,若年两相同则按照id升序排序
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("id", 2).orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
personagem de fuga
- >:gt
- <:lt
- =:eq
- >=:ge
- <=:o
- != : é
O construtor condicional implementa a operação de exclusão
//删除邮箱地址为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
int i = userMapper.delete(queryWrapper);
System.out.println(i);
Implementando operações de modificação usando construtores condicionais
//将年龄>20并且用户名中包含a或邮箱为null的用户进行修改(默认情况下就是and连接)
//修改条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20).like("name", "a").or().isNull("email");
User user = new User();
user.setName("lei").setEmail("[email protected]");
int i = userMapper.update(user, queryWrapper);
System.out.println(i);
Prioridade das condições
//将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息进行修改
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//lambda中的条件优先执行(i就表示条件构造器)
queryWrapper.like("name", "a").and(i-> i.gt("age", 20).or().isNull("email"));
User user = new User();
user.setName("red").setEmail("[email protected]");
int i = userMapper.update(user, queryWrapper);
System.out.println(i);
Montando a instrução select
//查询出来一个以map为泛型的list集合
//查询用户名、年龄、邮箱信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name","age","email");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
System.out.println(maps);
Montando uma subconsulta
//select * from t_user where id in(select id from t_user where id<=100)
//查询id<=100的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "select id from t_user where id<=100");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
consulta SQL dinâmica
String name=null;
String age="21";
//判断字符串是否为null或空串若为返回false,不为返回true
boolean pn = StringUtils.hasLength(name);
boolean pa = StringUtils.hasLength(age);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//判断属性是否为true,为true则执行该条件,不为则忽略该条件
queryWrapper.eq(pn,"name",name).eq(pa, "age", age);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
Nota: queryWrapper.clear(); Para limpar condições redundantes, queryWrapper pode continuar a ser usado após a limpeza
Use updateWrapper para implementar a função de modificação
//查询用户名中包含a(年龄>20或邮箱为null)的员工信息
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//修改条件
updateWrapper.like("name", "a").and(i->i.gt("age", 20).isNull("email"));
//修改内容
updateWrapper.set("name", "lala").set("email", "[email protected]");
int i = userMapper.update(null, updateWrapper);
System.out.println(i);
LambdaQueryWrapper
Função: evitar que sejamos muito estúpidos e escrever o nome do campo errado e fornecer uma interface funcional para acessar um determinado atributo em nossa classe de entidade.Quando acessamos o atributo, ele pode obter automaticamente o campo correspondente do atributo Nome, que campo a ser usado como condição
String name="a";
Integer ageBegin=null;
Integer ageEnd=30;
//主要避免了名称写错进而提供了直接访问表达式::
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(StringUtils.isNotBlank(name), User::getName,name)
.ge(ageBegin!=null, User::getAge,ageBegin)
.le(ageEnd!=null, User::getAge,ageEnd);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
System.out.println(users);
LambdaUpdateWrapper
//查询用户名中包含a(年龄>20或邮箱为null)的员工信息
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
//修改条件
updateWrapper.like(User::getName, "a").and(i->i.gt(User::getAge, 20).isNull(User::getEmail));
//修改内容
updateWrapper.set(User::getName, "lala").set(User::getEmail, "[email protected]");
int i = userMapper.update(null, updateWrapper);
System.out.println(i);
Plugin de paginação para MP
Classe de configuração de configuração (necessária)
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//创建mybatisplus拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//向拦截器中添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
MP implementa paginação
//测试类内
//两个参数——当前页页码,每页信息条数
Page<User> page = new Page<>(2,3);
//两个参数——分页对象,条件构造器
userMapper.selectPage(page, null);//因为我对所有的查询所以条件构造器为null——返回值还为page
//获取当前页数据
List<User> records = page.getRecords();
System.out.println(records);
//获取总记录数
long total = page.getTotal();
System.out.println(total);
//获取总页数
long pages = page.getPages();
System.out.println(pages);
//是否有下一页
System.out.println(page.hasNext());
//是否有上一页
System.out.println(page.hasPrevious());
Função de paginação personalizada
//自定义接口:
//mybatisplus提供的分页对象,必须为于第一个参数的位置
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
//自定义配置文件sql
<select id="selectPageVo" resultType="User">
select id,name,age,email from t_user where age>#{age}
</select>
//测试类
Page<User> page = new Page<>(2, 2);
userMapper.selectPageVo(page,20);
//获取当前页数据
List<User> records = page.getRecords();
System.out.println(records);
//获取总记录数
long total = page.getTotal();
System.out.println(total);
//获取总页数
long pages = page.getPages();
System.out.println(pages);
//是否有下一页
System.out.println(page.hasNext());
//是否有上一页
System.out.println(page.hasPrevious());
Bloqueio otimista de MP
Adicione uma anotação de versão à classe de entidade que precisa ser alterada
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version//用来标识乐观锁版本号字段
private Integer version;
}
Adicionar plugin de bloqueio otimista
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//创建mybatisplus拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//向拦截器中添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
teste
Nota: Xiao Wang e Xiao Li abaixo usam os mesmos dados
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李"+productLi.getPrice());
//小王查询商品价格
Product productWang = productMapper.selectById(1);
System.out.println("小王"+productWang.getPrice());
//小李将商品价格+50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格-30
productWang.setPrice(productWang.getPrice()-30);
int result = productMapper.updateById(productWang);
if (result==0){
//操作失败后重试
Product productNew = productMapper.selectById(1);
productNew.setPrice(productNew.getPrice()-30);
productMapper.updateById(productNew);
}
Enumeração genérica
Há um tipo de enumeração na classe de entidade, então como armazenar o tipo de enumeração no banco de dados
//为该枚举添加注解
@Getter
public enum SexEnum {
MALE(1,"男"),
FEMALE(2,"女");
@EnumValue//将注解所标识的属性的值存储到数据库中(因为数据库中存放的是数字)
private Integer sex;
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
Configurar pacote de verificação de enumeração geral
mybatis-plus.type-enums-package=cn.tedu.mybatisplus.enums
Insira um objeto enumerado no banco de dados
Função de preenchimento automático de MP
Adicionar classe de configuração
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("created", new Date(), metaObject);
this.setFieldValByName("updated", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updated", new Date(), metaObject);
}
}
Adicionar anotações a classes de entidades
@Data
@Accessors(chain = true)
public class Product {
private Long id;
private String name;
private Integer price;
//在插入数据时自动填充
@TableField(fill = FieldFill.INSERT)
private Date created;
//在插入和更新操作时自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated;
@Version//用来标识乐观锁版本号字段
private Integer version;
}
teste
//测试
Product product = new Product();
product.setName("cake").setId(3L).setPrice(66);
int insert = productMapper.insert(product);
System.out.println(insert);