乐观锁
在面试过程中,我们经常会被问道乐观锁,悲观锁,这个起始是非常简单
乐观锁:顾名思义乐观锁。他总是认为不会出现问题,无论干什么都会不上锁,如果出现了问题,再次更新值的测试
悲观锁:顾名思义,他总是认为会出现问题,什么时候先上锁,再去操作
我们主要理解乐观锁机制
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
乐观锁:1.先查询获得版本号 version = version+1 -- A update user set name = hyc, version = version+1\ where id = 2 and vsersion=1 -- B如果b线程抢先完成,这个时候 vsersion =2 会导致A修改失败 update user set name = hyc, version = version+1 where id = 2 and vsersion=1
测试一下,MP的乐观锁插件
数据库添加字段,version
更新实体类
@Version private int version;
注册组件,编写version配置类
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
测试
//乐观锁成功的情况,单线程下,一定成功 @Test void contextLoads2() { user user = new user(); user.setId(1419289393067204614l); user.setAge(3); user.setName("保证我一路畅通无阻"); user.setEmail("3132774018@qq.com"); int result = usermapper.updateById(user); System.out.println(result); System.out.println(user); } // 模拟多线程,测试乐观锁,被抢先的情况 @Test void contextLoads3() { user userSel = usermapper.selectById(1l); userSel.setId(1l); userSel.setAge(3); userSel.setName("保证我一路畅通无阻000"); userSel.setEmail("3132774018@qq.com"); user userSel1 = usermapper.selectById(1l); userSel1.setId(1l); userSel1.setAge(3); userSel1.setName("保证我一路畅通无阻111"); userSel1.setEmail("3132774018@qq.com"); int result1 = usermapper.updateById(userSel1); int result = usermapper.updateById(userSel); } }
乐观锁线程插队了的结果
查询操作
代码示例
单个查询
user userSel = usermapper.selectById(1l);
System.out.println(userSel);
批量查询
List<user> userList = usermapper.selectBatchIds(Arrays.asList(1, 2, 3));
userList.forEach(System.out::println);
条件查询
HashMap<String,Object> map = new HashMap<>();
map.put("name","保证我一路畅通无阻");
List<user> users = usermapper.selectByMap(map);
users.forEach(System.out::println);
分页查询
分页在网站使用的·十分之多
原始的limit分页
pageHelper第三方
MP其实也内置了分页插件
怎么使用的?
1、MP分页插件组件导入
@Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); // 开启 count 的 join 优化,只针对部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; }
2、直接使用Page对象即可!
//测试分页查询 @Test void selectByPage(){ //参数一:当前页,参数二:页面条数大小 Page<user> page = new Page<>(1,5); usermapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
删除操作
代码示例:
//删除 @Test void deleteByid(){ usermapper.deleteById(1l); } //批量按id删除 @Test void deleteBybatchid(){ usermapper.deleteBatchIds(Arrays.asList(1419289393067204612l,1419289393067204613l)); } //根据map条件删除 @Test void deleteBymapid(){ HashMap<String, Object> map = new HashMap<>(); map.put("id","1419289393067204614"); usermapper.deleteByMap(map); }
在工作中会遇到一些问题,逻辑删除
逻辑删除
物理删除:从数据库直接移除
逻辑删除:再数据库中没有溢出,而是通过一个变量来让他失效!
常见功能:管理员可以查看被删除的记录,防止数据的丢失,类似于回收站
测试一下:
在数据表中添加一个deleted字段,
更新实体类,我们在需要代表逻辑删除的orm对象上添加@TABLELOGIC来代表逻辑删除
@TableLogic
private int deleted;
逻辑删除组件配置
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
配置文件,对应的数据库字段是deleted,0,1
#逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
测试,我们执行的是删除,但是走的却是更新语句,改变的是逻辑删除的字段,
我们再查看数据库,记录还在,只是字段被更新了;逻辑删除的字段
我们再去查寻的时候,deleted为1就是被删除后,他会自动拼接到之后的sql中,加入只查询deleted为0的字段
以上的所有crud及其扩展操作,我们都必须精通掌握,会大大提高效率
性能分析插件(新版本弃用了)新版本有替代的新分析
我们在平时的开发中,会遇到一些慢sql。测试,druid
MP也提供了性能分析插件,如果超过了时间就停止运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fKKWeBI-1629731482783)(mybatisplus.assets/image-20210726092011898.png)]
导入之后执行sql就会有相应的东西了
只要超过了规定的执行的时间,就抛出异常
好处:
条件构造器 warpper
十分重要,:warpper
我们写一些复杂的sql就可以用它来代替
我们的所有条件都可以用这个构造器来使用
PS: 记得查看输出的sql进行分析
测试一,
@Test
void contextLoads() {
QueryWrapper<user> wrapper = new QueryWrapper();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
usermapper.selectList(wrapper).forEach(System.out::println);
}
测试二
@Test
void Test2(){
//right和left的区别 %t,t%
QueryWrapper<user> wrapper = new QueryWrapper();
wrapper
.notLike("name","e")
.likeRight("email","t");
List<Map<String, Object>> maps = usermapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
剩下的自己测试
代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
需要依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
记得导入自己的模版引擎需要的依赖,这里我们测试使用的是默认的
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>latest-velocity-version</version>
</dependency>
测试:配置好的代码生成器
//构建一个代码生成器对象 AutoGenerator generator = new AutoGenerator(); //配置策略 //1.全局配置 GlobalConfig gc = new GlobalConfig(); String projectpath = System.getProperty("user.dir");//项目地址 gc.setOutputDir(projectpath+"/src/main/java"); gc.setAuthor("hyc"); gc.setOpen(false); gc.setFileOverride(false);//是否覆盖 gc.setServiceImplName("%sService");//接口前缀,不要 gc.setIdType(IdType.ID_WORKER);//策略id gc.setDateType(DateType.ONLY_DATE);//时间类型 gc.setSwagger2(true);//开启Swagger generator.setGlobalConfig(gc); //2.数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"); dsc.setDbType(DbType.MYSQL);//这只数据库 generator.setDataSource(dsc); //3.包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName("blog"); pc.setParent("com.hyc"); pc.setEntity("pojo"); pc.setMapper("mapper"); pc.setService("Service"); pc.setController("controller"); generator.setPackageInfo(pc); //策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("user");//配置映射的表名可以写很多个比如:user,role,region strategy.setNaming(NamingStrategy.underline_to_camel);//驼峰 strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库的名字转换 strategy.setEntityLombokModel(true);//是否开启lombok strategy.setRestControllerStyle(true); //逻辑删除 strategy.setLogicDeleteFieldName("deleted"); //自动填充 TableFill gmtcreate =new TableFill("create_time", FieldFill.INSERT);//再新增的时候填充 TableFill gmtupd=new TableFill("update_time", FieldFill.INSERT_UPDATE);//再新增和更新的时候填充 ArrayList<TableFill> tablefill = new ArrayList<>(); tablefill.add(gmtcreate); tablefill.add(gmtupd); strategy.setTableFillList(tablefill); //乐观锁 strategy.setVersionFieldName("version");//sersion叫变量 strategy.setRestControllerStyle(true);//开启restful风格接口 strategy.setControllerMappingHyphenStyle(true);//请求风格,localhost/v1/id_ps_.. generator.setStrategy(strategy); generator.execute();
效果: