1. 逻辑删除 94
前面我们完成了基本的增删改查操作,但是对于删除操作来说,我们思考一个问题,在实际开发中我们真的会将数据完成从数据库中删除掉么?
当然是不会的,这里我们举个例子:
在电商网站中,我们会上架很多商品,这些商品下架以后,我们如果将这些商品从数据库中删除,那么在年底统计商品数据信息的时候,这个商品要统计的,所以这个商品信息我们是不能删除的。
如果商城中的商品下架了,这时候我们将商品从数据库删掉
那到了年终总结的时候,我们要总结一下这一年的销售额,发现少了20000,这肯定不合理。所以我们是不能将数据真实删除的。
这里我们就采取逻辑删除的方案,逻辑删除的操作就是增加一个字段表示这个数据的状态,如果一条数据需要删除,我们通过改变这条数据的状态来实现,这样既可以表示这条数据是删除的状态,又保留了数据以便以后统计,我们来实现一下这个效果。
1.1 演示逻辑删除 95
【1】先在表中增加一列字段,表示是否删除的状态,这里我们使用的字段类型为int类型,通过1表示该条数据可用,0表示该条数据不可用
【2】实体类添加一个字段为Integer,用于对应表中的字段
//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
public class User extends Model<User>{
@TableId
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic(value = "1",delval = "0")//指定当前字段为逻辑删除字段 95
private Integer status;
}
【3】测试逻辑删除效果
LoginTest
package com.powernode;
import com.powernode.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
//测试逻辑删除 95
@SpringBootTest
public class LoginTest {
@Autowired
private UserMapper userMapper;
@Test
void loginDelete(){
userMapper.deleteById(7L);
}
}
查看拼接的SQL语句,我们发现在执行删除操作的时候,语句变成了修改,是将这条数据的状态由1变为的0,表示这条数据为删除状态
查询一下看看这条数据还能不能查询出来
LoginTest
//查询一下看看这条数据还能不能查询出来 95
@Test
void logicSelect(){
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
List<User> users = userMapper.selectList(lambdaQueryWrapper);
System.out.println(users);
}
我们还可以通过全局配置来实现逻辑删除的效果
2. 通用枚举 96
首先我们先来回顾一下枚举,什么是枚举呢?
当我们想要表示一组信息,这组信息只能从一些固定的值中进行选择,不能随意写,在这种场景下,枚举就非常的合适。
例如我们想要表示性别,性别只有两个值,要么是男性,要么是女性,那我们就可以使用枚举来描述性别。
【1】我们先在表中添加一个字段,表示性别,这里我们一般使用int来描述,因为int类型可以通过0和1这两个值来表示两个不同的性别
【2】编写枚举类
GenderEnum
package com.powernode.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
//性别的枚举类 96
public enum GenderEnum {
MAN(0,"男"),WOMAN(1,"女");
private Integer gender;
private String genderName;
GenderEnum(Integer gender, String genderName) {
this.gender = gender;
this.genderName = genderName;
}
}
【3】实体类添加相关字段
package com.powernode.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.powernode.enums.GenderEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
//@TableName("powershop_user") //指定数据库中的powershop_user表和这个User实体类映射 30
public class User extends Model<User> {
//@TableId(type = IdType.AUTO) //指定id的自增策略 (跟随我们数据库的主键自增策略来的) 77
//@TableId(type = IdType.INPUT)//主键该策略表示,必须由我们手动的插入id,否则无法添加数据 78
//@TableId(type = IdType.ASSIGN_ID)//测试雪花算法 81
@TableId(type = IdType.NONE)//NONE策略表示不指定主键生成策略,他跟随的是全局策略 82
private Long id;
*//*@TableId(type = IdType.ASSIGN_UUID) //UUID全局唯一标识符定义了在时间和空间都完全唯一的系统信息 83
private String id;*//*
// @TableField("username") //指定表中的字段名和属性对应 32
private String name;
// @TableField(select = false)//时age字段失效查询不到 34
private Integer age;
private String email;
// @TableField("`desc`") //将desc字段变成普通字段 33
// private String desc;
//online属性在表中没有,但是我们有需要这个属性进行展示,所以使用TableField注解, 35
// 去掉这个字段,不让他作为查询字段。
// @TableField(exist = false)
// private Integer online; //用户在线或不在线
}*/
//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
public class User extends Model<User>{
@TableId
private Long id;
private String name;
private Integer age;
private String email;
// @TableLogic(value = "1",delval = "0")//指定当前字段为逻辑删除字段 95
private Integer status;
private GenderEnum gender;
}
【4】添加数据
package com.powernode;
import com.powernode.domain.User;
import com.powernode.enums.GenderEnum;
import com.powernode.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
//测试性别枚举 96
@SpringBootTest
public class EnumTest {
@Autowired
private UserMapper userMapper;
@Test
void enumTest(){
User user = new User();
user.setName("liu");
user.setAge(29);
user.setEmail("[email protected]");
user.setStatus(1);
user.setGender(GenderEnum.WOMAN);
userMapper.insert(user);
}
}
此时我们查看控制台,会发现添加失败了
原因是我们无法将一个枚举类型作为int数字插入到数据库中。不过我们对于枚举类型都给了对应的int的值,所以这里我们只需要进行一个配置,就可以将枚举类型作为数字插入到数据库中,为属性gender,添加上@EnumValue注解
package com.powernode.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
//性别的枚举类 96
public enum GenderEnum {
MAN(0,"男"),WOMAN(1,"女");
@EnumValue
private Integer gender;
private String genderName;
GenderEnum(Integer gender, String genderName) {
this.gender = gender;
this.genderName = genderName;
}
}
此时我们再次执行添加操作,发现可以成功添加数据,而枚举类型的值也作为数据被插入到数据库中
3. 字段类型处理器 98
在某些场景下,我们在实体类中是使用Map集合作为属性接收前端传递过来的数据的,但是这些数据存储在数据库时,我们使用的是json格式的数据进行存储,json本质是一个字符串,就是varchar类型。那怎么做到实体类的Map类型和数据库的varchar类型的互相转换,这里就需要使用到字段类型处理器来完成。
【1】我们先在实体类中添加一个字段,Map类型
//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
@TableName(autoResultMap = true)//将数据库查到的数据封装到map中 98
public class User extends Model<User>{
@TableId
private Long id;
private String name;
private Integer age;
private String email;
// @TableLogic(value = "1",delval = "0")//指定当前字段为逻辑删除字段 95
private Integer status;
private GenderEnum gender;
//指定这个字段存储到数据库,将map处理器变成json格式 98
@TableField(typeHandler = FastjsonTypeHandler.class)
private Map<String,String> contact;//联系方式 98
}
【2】在数据库中我们添加一个字段,为varchar类型
【3】为实体类添加上对应的注解,实现使用字段类型处理器进行不同类型数据转换
@TableName(autoResultMap = true)//将数据库查到的数据封装到map中 98
【4】字段类型处理器依赖Fastjson这个Json处理器,所以我们需要引入对应的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
【5】测试添加操作 98
TypeHandlerTest
//向数据库添加一条数据 98
@Test
void typeHandler(){
User user = new User();
user.setName("li");
user.setAge(28);
user.setEmail("[email protected]");
user.setGender(GenderEnum.MAN);
user.setStatus(1);
HashMap<String, String> map = new HashMap<>();
map.put("tel","13388889999");
map.put("phone","010-1234567");
user.setContact(map);
userMapper.insert(user);
}
执行的SQL语句如下
通过观察SQL语句,我们发现当插入一个Map类型的字段的时候,该字段会转换为String类型
查看数据库中的信息,发现添加成功
【6】测试查询操作,通过结果发现,从数据库中查询出来的数据,已经被转到Map集合
//查询 98
@Test
void typeHandlerSelect(){
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
4. 自动填充功能 99
在项目中有一些属性,如果我们不希望每次都填充的话,我们可以设置为自动填充,比如常见的时间,创建时间和更新时间可以设置为自动填充。
【1】在数据库的表中添加两个字段 99
注意只有设置了下划线和小驼峰映射,这种mysql的写法才能和实体类完成映射
【2】在实体类中,添加对应字段,并为需要自动填充的属性指定填充时机
//数据库对应的实体类user 4
@Data //生成set get方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
@TableName(autoResultMap = true)//将数据库查到的数据封装到map中 98
public class User extends Model<User>{
@TableId
private Long id;
private String name;
private Integer age;
private String email;
// @TableLogic(value = "1",delval = "0")//指定当前字段为逻辑删除字段 95
private Integer status;
private GenderEnum gender;
//指定这个字段存储到数据库,将map处理器变成json格式 98
@TableField(typeHandler = FastjsonTypeHandler.class)
private Map<String,String> contact;//联系方式 98
@TableField(fill = FieldFill.INSERT) //设置插入时自动填充 99
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//设置插入和更新时自动填充 99
private Date updateTime;
}
【3】编写自动填充处理器,指定填充策略 99
MyMetaHandler
package com.powernode.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
//配置填充策略 99
@Component
public class MyMetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
setFieldValByName("createTime",new Date(),metaObject);
setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
setFieldValByName("updateTime",new Date(),metaObject);
}
}
【4】这里在插入前先设置一下mysql时区
set GLOBAL time_zone = '+8:00'
通过查看发现,目前时区时间正常
SELECT NOW()
【5】再将配置文件的时区修改为serverTimezone=Asia/Shanghai
【6】测试插入操作 99
FillTest
@Test
void testFillInsert(){
User user = new User();
user.setName("wang");
user.setAge(35);
user.setEmail("[email protected]");
user.setGender(GenderEnum.MAN);
user.setStatus(1);
HashMap<String, String> contact = new HashMap<>();
contact.put("phone","010-1234567");
contact.put("tel","13388889999");
userMapper.insert(user);
}
【7】测试更新操作 99
FillTest
//更新
@Test
void testFillUpdate(){
//1682337035187712001
User user = new User();
user.setId(1682337035187712001L);
user.setName("wangwu");
user.setAge(39);
user.setEmail("[email protected]");
user.setGender(GenderEnum.MAN);
user.setStatus(1);
HashMap<String, String> contact = new HashMap<>();
contact.put("phone","010-1234567");
contact.put("tel","13388889999");
userMapper.updateById(user);
}
5. 防全表更新与删除插件 100
在实际开发中,全表更新和删除是非常危险的操作,在MybatisPlus中,提供了插件和防止这种危险操作的发生
先演示一下全表更新的场景
这是很危险的
如何解决呢?
注入MybatisPlusInterceptor类,并配置BlockAttackInnerInterceptor拦截器
MybatisPlusConfig
package com.powernode.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//配置类 85
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//这个是配置 防全表更新与删除拦截器 100
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
//这里我们配置分页插件 85
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
测试全表更新,会出现抛出异常,防止了全表更新
UpdateAllTest
package com.powernode;
import com.powernode.domain.User;
import com.powernode.enums.GenderEnum;
import com.powernode.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
//测试防全表更新与删除插件 100
@SpringBootTest
public class UpdateAllTest {
@Autowired
private UserService userService;
@Test
public void updateAll(){
User user = new User();
user.setGender(GenderEnum.MAN);
//更新性别为男 原本null这个参数是要写条件的,null表示没有条件,即表中数据全部更新 100
userService.saveOrUpdate(user,null);
}
}
测试,ok 拦截住了全表更新
标签:mybatisplus,数据库,private,powernode,拓展,import,com,user From: https://blog.51cto.com/u_15784725/6899871