目录
1、主键自增
1.1、id自增策略
1.2、id主键自增不连续
2、自动填充数据功能
代码级别
1)使用注解@TableField
2)数据库中新增字段
3)自定义实现类处理注解
3)测试
数据库级别
3、代码生成器
方式一:下插件
方式二:写代码
4、逻辑删除
1)数据库中添加字段
2)实体类上加注解
3)配置文件
4)测试
4、条件构造器
5、乐观锁
5.1、实现方式:
5.2、实现步骤
5.3、测试乐观锁
1、主键自增
1.1、id自增策略
@TableId(type = IdType.AUTO)
private Integer id;
从源码中可以看到,除了AUTO这个策略以外,还有如下几种生成策略:
- NONE: 不设置id生成策略
- INPUT:用户手工输入id
- ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)
- ASSIGN_UUID:以UUID生成算法作为id生成策略
其他的几个策略均已过时,都将被ASSIGN_ID和ASSIGN_UUID代替掉。
1.2、id主键自增不连续
在使用idea删除数据时,id自增会自动从删除的id号向上加1,导致不连续
执行语句:
1)若删完数据后还未新增,
# 缺点:每次删完数据,想再插入一条数据前,都要
ALTER TABLE user3 AUTO_INCREMENT=1;
2)若表中已出现不连贯的数据ID,
set @auto_id=0;
update 表名 set 自增字段名 = (@auto_id :=@auto_id+1);
ALTER TABLE user3 AUTO_INCREMENT=1;
2.1)先使用truncate来删除表数据
truncate table 表名
2.2)执行语句
ALTER TABLE 表名 AUTO_INCREMENT=1;
2、自动填充数据功能
当数据进行添加或修改时,自动为字段填充数据,常用业务中有些属性需要配置默认值,
比如创建时间、修改时间,这些操作都是自动化完成的,不需要手动去更新
添加或修改数据时每次都需要使用相同的方式进行填充
MP支持自动填充这些字段的数据
方法:
数据库级别 代码级别
代码级别
1)使用注解@TableField
标注需要进行填充的字段updateTime/createTime
实体类中修改
@TableField(fill = FieldFill.INSERT,value = "createTime")
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE,value = "updateTime")
private Date updateTime;
2)数据库中新增字段
createTime和updateTime
3)自定义实现类处理注解
import java.util.Date;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("create_time",new Date(),metaObject);
this.setFieldValByName("update_time",new Date(),metaObject);
}
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("update_time",new Date(),metaObject);
}
}
3)测试
@Test
void test01(){
Users users=new Users();
users.setName("ss");
users.setAge(1);
users.setCreateTime(new Date());
users.setUpdateTime(new Date());
int row=userMapper.updateById(users);
System.out.println(row);
}
结果:
字段更新成功,数据自动填充
数据库级别
删除注解
不需要处理类
勾选图中的部分
3、代码生成器
方式一:下插件
EasyCode是一个代码生成插件用于自动生成Entity\controller、Service
功能:
- 支持多表同时操作
- 支持同时生成多个模板
- 支持自定义模板
- 支持自定义类型映射
- 支持自定义附加列
- 支持列附加属性
方式二:写代码
1、pom.xml文件下导包
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
2、编写配置类添加乐观锁拦截器
@SpringBootApplication
public class Mybatisplus04GeneratorApplication {
public static void main(String[] args) {
SpringApplication.run(Mybatisplus04GeneratorApplication.class, args);
}
}
3、创建代码生成器类
public class CodeGenerator {
public static void main(String[] args) {
//1.获取代码生成器的对象
AutoGenerator autoGenerator = new AutoGenerator();
//设置数据库相关配置
DataSourceConfig dataSource = new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
//设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
//设置包名相关配置
PackageConfig packageInfo = new PackageConfig();
packageInfo.setParent("com.aaa"); //设置生成的包名,与代码所在位置不冲突
packageInfo.setEntity("domain"); //设置实体类包名
packageInfo.setMapper("dao"); //设置数据层包名
autoGenerator.setPackageInfo(packageInfo);
//执行代码生成操作
autoGenerator.execute();
}
4、逻辑删除
普通的增删改查这里就不演示了
删除操作分为两种:
物理删除:数据库中直接删除
逻辑删除:在数据库中没有被删除而是通过一个变量使它失效
delete=0
1)数据库中添加字段
默认值为0,表示没有被删除
2)实体类上加注解
//逻辑删除
@TableLogic
private Integer deleted;
3)配置文件
# 配置逻辑删除
# 全局逻辑删除的实体字段名
mybatis-plus.global-config.db-config.logic-delete-field=flag
# 逻辑已删除默认为1
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值默认为0
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4)测试
@Test
void delete(){
int a = userMapper.deleteById(0);
System.out.println(a);
}
结果:
4、条件构造器
MyBatis-Plus自带的四种lambda条件构造器
1、new LambdaQueryWrapper<>()
LambdaQueryWrapper<User> lambda=new LambdaQueryWrapper<>();
lambda.eq(user::getUsername,username);
User user=userMapper.select--(lambda);
2、new QueryWrapper<实体类>().lambda()
LambdaQueryWrapper<user> lambda=new QueryWrapper<User>().lambda();
lambda.eq(User::getUsername,username);
User user=userMapper.select--(lambda);
3、Wrappers.<User>lambdaQuery()
LambdaQueryWrapper<user> lambda=Wrappers.<User>lambdaQuery();
lambda.eq(User::getUsername,username);
User user=userMapper.select--(lambda);
5、乐观锁
业务并发现象带来的问题:秒杀
假如有100个商品或者票在出售,为了能保证每个商品或者票只能被一个人购买,如何保证不会出
现超买或者重复卖
对于这一类问题,其实有很多的解决方案可以使用
第一个最先想到的就是锁,锁在一台服务器中是可以解决的,但是如果在多台服务器下锁就没有办
法控制,比如12306有两台服务器在进行卖票,在两台服务器上都添加锁的话,那也有可能会导致
在同一时刻有两个线程在进行卖票,还是会出现并发问题
乐观锁:认为不会出现问题,无论干什么都不会上锁,如果出现问题,就再次更新测试值
操作数据的时候不会对数据进行枷锁(可使多个任务可以并行对数据操作),只有在提交的时候才通过机制来验证数据是否存在冲突
5.1、实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时,set version=newVersion where version=oldVersion
如果version不对就更新失败
5.2、实现步骤
1)数据库添加字段version
2)实体类
@Version
private Integer version;
3)配置插件
springboot注解方式
创建配置类
@Configuration
@EnableTransactionManagement//自动管理事务,默认开启
public class MPConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
5.3、测试乐观锁
1)成功的测试
//测试成功的乐观锁
@Test
void testLock01(){
//查询用户
Users users=userMapper.selectById(4);
//修改信息
users.setAge(89);
users.setName("硝烟");
//执行更新
userMapper.updateById(users);
}
我们传递的是1,MP会将1进行加1,然后,更新回到数据库表中。
所以要想实现乐观锁,首先第一步应该是拿到表中的version,然后拿version当条件在将version
加1更新回到数据库表中,所以我们在查询的时候,需要对其进行查询
2)失败的测试
模拟用户抢票
//测试失败的乐观锁
@Test
void testLock02(){
//模拟多线程实现插队
//线程一
Users user1=userMapper.selectById(4);
//修改信息
user1.setAge(99);
user1.setName("天使");
//线程二
Users user2=userMapper.selectById(4);
//修改信息
user2.setAge(23);
user2.setName("昊天");
//在这里插队
userMapper.updateById(user2);
//如果没有乐观锁,就会覆盖插队线程的值
userMapper.updateById(user1);
}