mybatisplus学习——(2)操作
目录
1、配置日志
#配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2、插入(insert)
@Test
public void testInsert(){
User user = new User();
user.setName("孙日天");
user.setAge(22);
user.setEmail("348484@qq.com");
int result = userMapper.insert(user);
System.out.println(result);
}
数据库插入的id的默认值:全局的唯一id
3、主键生成策略
分布式系统唯一id生成:雪花算法
3.1、雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个Long型ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器数的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!
主键自增
我们需要配置主键自增:
1、实体类字段上@TableId(type = IdType.AUTO)
2、数据库字段一定要是自增!
public enum IdType {
AUTO(0), //数据库id自增
NONE(1), //未设置主键
INPUT(2), //手动输入
ASSIGN_ID(3),
ASSIGN_UUID(4), //全局唯一id uuid
/** @deprecated */
@Deprecated
ID_WORKER(3),
/** @deprecated */
@Deprecated
ID_WORKER_STR(3),
/** @deprecated */
@Deprecated
UUID(4);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
4、更新
@Test
public void testUpdate(){
User user = new User();
//通过条件,自动拼接SQL
user.setId(6L);
user.setName("关注公众号狂神说");
user.setAge(18);
int result = userMapper.updateById(user);
System.out.println(result);
}
所有的sql都是自动动态配置!
5、自动填充
创建时间、修改时间!这些个操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_created、gmt_modified几乎所有的表都要配置上!而且需要自动化!
方式一:数据库级别(工作中不允许使用)
1、在表中新增字段created_at(created_time)、updated_at(updated_time)
2、再次测试插入方法,先同步实体类!
public class User {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private Integer age;
private String email;
private Date createTime;
private Date updateTime;
}
3、再次更新查看结果!
方式二:代码级别
1、删除数据库的默认值、更新操作!
2、实体类字段属性上需要增加注释
public class User {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
3、编写处理器来处理这个注解即可!
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill......");
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、测试
6、乐观锁
乐观锁:它总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新值测试
悲观锁:它总是认为会出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
// 乐观锁:1、先查询,获得版本号version = 1
// 线程A
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
// 线程B
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
测试一下mybatisplus的乐观锁插件
1、给数据库表中增加version字段
2、实体类加对应的字段
// 乐观锁Version注解
@Version
private Integer version;
3、注册组件
@EnableTransactionManagement
@MapperScan("com.sun.*")
@Configuration
@Deprecated
public class MyBatisPlusConfig {
/**
* MybatisPlus最新版已经弃用
* @return
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4、测试
/**
* 测试乐观锁成功
*/
@Test
public void testOptimisticLocker(){
// 1、查询用户信息
User user = userMapper.selectById(1L);
// 2、修改用户信息
user.setName("kuangshen");
user.setEmail("24736743@qq.com");
// 3、执行更新操作
userMapper.updateById(user);
}
/**
* 测试乐观锁失败 多线程下
*/
@Test
public void testOptimisticLocker2(){
// 线程1
User user = userMapper.selectById(1L);
user.setName("kuangshen111");
user.setEmail("24736743@qq.com");
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user.setName("kuangshen222");
user.setEmail("24736743@qq.com");
userMapper.updateById(user2);
// 如果没有乐观锁就会覆盖插队线程的值
// 自旋锁来尝试多次提交!
userMapper.updateById(user);
}
7、查询
/**
* 测试查询
*/
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
/**
* 测试批量查询
*/
@Test
public void testSelectByBatchIds(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
users.forEach(System.out::println);
}
/**
* 条件查询之一-使用map操作
*/
@Test
public void testSelectByMap(){
HashMap<String, Object> map = new HashMap<>();
// 自定义要查询的条件
map.put("name","kuangshen");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
8、分页查询
1、原始的limit进行分页
2、pageHelper第三方插件
3、MP内置分页插件
如何使用!
1、配置拦截器组件即可
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
2、测试
/**
* 测试分页查询
*/
@Test
public void testPage(){
/*
* @Param 当前页
* @Param 页面大小
*/
Page<User> page = new Page<>(1,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
9、删除
基本的删除操作
/**
* 测试删除
*/
@Test
public void testDeleteById(){
userMapper.deleteById(5L);
}
/**
* 通过id批量删除
*/
@Test
public void testDeleteBatchIds(){
userMapper.deleteBatchIds(Arrays.asList(3,4));
}
/**
* 通过map删除
*/
@Test
public void testDeleteByMap(){
HashMap<String,Object> map = new HashMap<>();
map.put("name","Billie");
userMapper.deleteByMap(map);
}
10、逻辑删除
物理删除:从数据库中直接移除
逻辑删除: 数据库中没有被移除,而是通过一个变量来让它失效!deleted = 0 =》 deleted = 1
管理员可以查看被删除的记录!防止数据丢失,类似于回收站!
测试:
1、在数据表中增加一个deleted字段
2、实体类中增加属性
// 逻辑删除
@TableLogic
private Integer deleted;
3、配置
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
记录依旧在数据库中,但是值确已经变化了