CRUD拓展
插入
@Test
public void insertTest(){
User user = new User();
user.setName("张三");
user.setAge(18);
user.setEmail("3107275811@qq.com");
int result = userMapper.insert(user);
System.out.println("结果 --> "+result);
System.out.println(user);
}
运行,查看日志
值得关注的是,id我们并没有赋值,mybatis-plus自动帮我们生成了
数据库插入的id默认值为:全局的唯一id
主键生成策略
默认 ID_WORKER 全局唯一id
分布式系统唯一id生成:https://www.jianshu.com/p/555584151ae4
雪花算法:
主键自增
1、实体类字段加上注解**@TableId(type=IdType.AUTO)**
2、数据库字段一定要是自增的
3、测试插入并查询
id自增
其他的源码解释
public enum IdType {
AUTO(0), //自增
NONE(1), //没有设置主键
INPUT(2), //手动输入
ID_WORKER(3), //雪花算法,默认全局唯一id
UUID(4), //uuid,全局唯一id
ID_WORKER_STR(5); //字符串截取id
private int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
更新
@Test
public void updateTest01(){
User user = new User();
user.setId(1L);
user.setName("张三");
user.setEmail("3107275811@qq.com");
//注意:updateById 但参数是一个对象!
userMapper.updateById(user);
}
运行,查看日志
在写一个测试更新方法
@Test
public void updateTest02(){
User user = new User();
user.setId(1L);
user.setName("张三");
user.setAge(18);
user.setEmail("3107275811@qq.com");
userMapper.updateById(user);
}
运行,查看日志
对比两个日志:可以发现mybatis-plus可以通过条件自动拼接动态sql
自动填充
创建时间,修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modifiled几乎所有的表都要配置上!而且需要自动化!
方法一:数据库级别(工作中不建议)
1、在数据库中加入create_time和update_time字段
2、实体类添加属性
private Date createTime;
private Date updateTime;
3、插入数据查看
方法二:代码级别
1、删除数据库默认和更新属性
2、实体类添加注解
@TableField(fill = FieldFill.INSERT) //插入时字段填充内容
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) //插入和更新时字段填充内容
private Date updateTime;
3、配置处理器(可以参考官网自动填充功能)
@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)
* fileName : 要填充的字段
* filedVal : 要插入的值
*/
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//更新时填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill。。。。");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、插入测试
成功!
乐观锁
乐观锁:顾名思义十分乐观。它总是认为不会出现问题,无论干什么都不去上锁,如果出现问题再次更新值测试
悲观锁:顾名思义十分悲观。它总是认为会出现问题,无论干什么都上锁,再去操作
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
实现乐观锁
1、数据库添加乐观锁字段
2、实体类加上字段属性
@Version //乐观锁注解
private Integer version;
3、注册组件
@EnableTransactionManagement //自动管理事务
@Configuration //代表这是一个配置类
@MapperScan("cn.yu.mapper") //将主程序类的mapperScan删除
public class MyBatisConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4、测试乐观锁成功
@Test
public void versionSuccess(){
User user = userMapper.selectById(1L);
user.setName("李四");
user.setEmail("3107275811@qq.com");
userMapper.updateById(user);
}
运行查看日志
可以发现更新时自带了version字段
5、测试乐观锁失败
@Test
public void versionFail(){
//线程1
User user01 = userMapper.selectById(2L);
user01.setName("李四");
user01.setEmail("3107275811@qq.com");
//线程2:模拟另一个线程执行插队操作
User user02 = userMapper.selectById(2L);
user02.setName("王五");
user02.setEmail("3107275811@qq.com");
userMapper.updateById(user01);//如果没有乐观锁,就会覆盖插队线程的值
userMapper.updateById(user02);
}
6、运行查看日志
李四更改成功,王五更改失败,多线程一定要加锁!
查询操作
//测试批量查询
@Test
public void selectTest(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
users.forEach(System.out::println);
}
//测试条件查询
@Test
public void whereTest(){
HashMap<String, Object> map = new HashMap<>();
//自定义查询条件
map.put("name","张三");
userMapper.selectByMap(map);
}
分页查询
1、配置拦截器组件
//注册分页插件
@Bean
public PaginationInterceptor paginationInnerInterceptor(){
return new PaginationInterceptor();
}
2、编写测试方法
//测试条件查询
@Test
public void whereTest(){
HashMap<String, Object> map = new HashMap<>();
//自定义查询条件
map.put("name","张三");
userMapper.selectByMap(map);
}
3、运行并查看日志
删除操作
基本的删除操作
//测试删除功能
@Test
public void deleteTest(){
int result = userMapper.deleteById(8L);
System.out.println("结果 --> " + result);
}
//通过批量删除
@Test
public void deleteBatchTest(){
HashMap<String, Object> map = new HashMap<>();
userMapper.deleteBatchIds(Arrays.asList(2L,6L));
}
//通过条件删除
@Test
public void deleteWhereTest(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","李四");
userMapper.deleteByMap(map);
}
逻辑删除
物理删除:从数据库直接删除
逻辑删除:在数据库中没有被删除,而是通过一个变量来让他失效!
管理员可以看到被删除的记录,防止数据丢失,类似于回收站!
实操
1、在数据库中增加一个recycle字段,默认值为0,表示未删除
2、实体类中增加属性
@TableLogic //逻辑删除注解
private Integer recycle;
3、配置拦截器组件
//注册逻辑删除插件
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
4、配置applcation.yaml
mybatis-plus:
global-config:
db-config:
logic-delete-field: recycle # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置逻辑删除注解)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
5、运行删除功能测试方法并查看日志
再次运行查询方法并查看日志