实体类的名字是User,数据库表名是t_user
@TableName(value = "t_user")
public class User {
默认情况下数据库的id列使用的是基于雪花算法的策略生成
随着业务规模的不断扩大,需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。
数据库的扩展方式主要包括:业务分库、主从复制,数据库分表。
将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如,淘宝的几亿用户数据,如果全部存放在一台数据库服务器的一张表中,肯定是无法满足性能要求的,此时就需要对单表数据进行拆分。
单表数据拆分有两种方式:垂直分表和水平分表。示意图如下:
垂直分表:
水平分表:
水平分表相比垂直分表,会引入更多的复杂性,例如数据id:
主键自增:
Hash :
雪花算法:
雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
实体类的属性名是 id,数据库的列名是 uid,此时使用 value 属性将属性名映射到列名
@TableId(value = "uid")
private String id;
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@TableId(type = IdType.AUTO)
private Long id;
全局配置:要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
功能同TableId的value属性
注意:MP会自动将数据库中的下划线命名风格转化为实体类中的驼峰命名风格
例如,数据库中的列 create_time 和 update_time 自动对应实体类中的 createTime 和 updateTime
private LocalDateTime createTime;
private LocalDateTime updateTime;
扩展知识:为什么建议使用你 LocalDateTime ,而不是 Date?为什么建议使用你 LocalDateTime ,而不是 Date? - 知乎
java.util.Date的大多数方法已经过时
java.util.Date的输出可读性差
java.util.Date对应的格式化类SimpleDateFormat是线程不安全的类。阿里巴巴开发手册中禁用static修饰SimpleDateFormat。
LocalDateTime 对应的格式化类DateTimeFormatter是线程安全的
2、自动填充
需求描述:
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作。
例如,阿里巴巴的开发手册中建议每个数据库表必须要有create_time 和 update_time字段,我们可以使用自动填充功能维护这两个字段
step1:添加fill属性
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
step2:实现元对象处理器接口 -> 创建handler包,创建MyMetaObjectHandler类
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
测试新增
测试修改
避免自动填充时开销过大,填充前先判断当前对象中是否有相关属性
@Override
public void insertFill(MetaObject metaObject) {
//其他代码
//判断是否具备author属性
boolean hasAuthor = metaObject.hasSetter("author");
if(hasAuthor){
log.info("start insert fill author....");
this.strictInsertFill(metaObject, "author", String.class, "Helen");
}
}
用户明确定义了属性值,则无需自动填充,否则使用自动填充
@TableField(fill = FieldFill.INSERT)
private Integer age;
@Override
public void insertFill(MetaObject metaObject) {
//其他代码
//判断age是否赋值
Object age = this.getFieldValByName("age", metaObject);
if(age == null){
log.info("start insert fill age....");
this.strictInsertFill(metaObject, "age", String.class, "18");
}
}
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
@TableLogic
@TableField(value = "is_deleted")
private Integer deleted;