4.5 测试插入
测试更新
4.6 乐观锁
乐观锁,非常乐观,干啥都不会上锁,如果出现问题,再次更新值测试
悲观锁,非常悲观,每次测试都需要上锁
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
1 查询时就先将version查出来 version=1 2,3 修改的时候将version也带上,这样就能使得资源安全 A线程 update set name="heihei" ,version=version + 1 where id=3 and version=1 B线程 update set name="heihei" ,version=version + 1 where id=3 and version=1 显然这样操作之后只有A线程能够正常执行,B线程就不能执行
测试乐观锁
修改表结构
修改实体类
@Version //乐观锁的Version注解 private Integer version;
注册组件
package com.rang.config; import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; //扫描我们的mapper文件夹 @MapperScan("com.rang.mapper") @EnableTransactionManagement //开启事务支持 @Configuration//配置类 public class MyBatisPlusConfig { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
测试乐观锁成功(单线程必定成功)
划重点!!!
这里提醒大家一下,大家可能会觉得我们有必要先查出用户的信息吗,能不能直接执行更新操作的,这里我们来测试一下,我们将测试的代码改成下面这样:
//乐观锁成功 @Test public void testOptimisticLocker1(){ // User user=userMapper.selectById(1L); User user=new User(); user.setId(1L); user.setName("爱你三千遍"); userMapper.updateById(user); }
测试之后我们发现
的确是执行了更新操作的,但是我们仔细看SQL语句能够发现他并有带上我们的version字段同时进行检测,所以说这样是不能够实现乐观锁的概念的,所以说本质上我们在执行操作的时候本质上都需要先查询一下该对象本质上就是查询出该对象的version字段,这样我们之后的操作才能够将version字段同时带进去进行检测,从而达到乐观锁的目的.
测试乐观锁失败
//乐观锁失败,多线程下 @Test public void testOptimisticLocker2(){ //线程1 User user1=userMapper.selectById(1L); user1.setName("要你命三千111"); //线程2插队 User user2=userMapper.selectById(1L); user2.setName("要你命三千222"); userMapper.updateById(user2); userMapper.updateById(user1);//如果没有乐观锁,就会覆盖插队线程的值 }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ag8v0lKx-1600775508479)(C:\Users\瓤瓤\AppData\Roaming\Typora\typora-user-images\1600738078637.png)]
这里我们可以发现 userMapper.updateById(user1) 这个方法是没有被执行的,这里的主要原因就如下图所示:
4.7 查询操作
查新单个信息
//查询单个用户 @Test public void testSelectByid(){ User user=userMapper.selectById(1L); System.out.println(user); }
查询多个信息
// 查询多个用户 @Test public void testSelectByBatchId(){ List<User> users=userMapper.selectBatchIds(Arrays.asList(1,2,3)); users.forEach(System.out::println); }
条件查询
//条件查询通过map集合封装我们的数据 @Test public void testSelectByBatchIds(){ HashMap<String,Object>map=new HashMap<>(); // 自定义条件查询 map.put("name","rangrang"); List<User> users= userMapper.selectByMap(map); users.forEach(System.out::println); }
4.8 分页查询
其实我自己的分页查询的真个学习历程就是这样的
一开始就是通过 limit与offset 两个参数来进行查询的,并且还要另外写一个SQL语句来读取数据的总量,这样就会使得我们的SQL语句显得十分的臃肿就如下图所示:
之后同事介绍我使用了 pagehelper 这个插件之后,自己那时候也是觉得真香,还特地写了篇博客来记录了一下,大家有兴趣的可以去看看:前后端分离使用pagehelper
他会很明显的减少我们的SQL语句编写的工作量,不用再加上limit这些参数,直接写出select语句即可,并且不用再另外写一个查询数据总量的SQL语句,但是他本身还是需要我们传入两个必要的参数page与size,之后在controller层对他进行操作实现分页查询的功能.
但是使用了 mybatis-plus 之后你就知道什么叫更香了,mybatis-plus的分页插件就显得更加的简单方便,同样的我们只需要在配置类中注册分页插件,之后我们就可以直接使用了
//注册分页插件 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
之后我们就可以直接使用了
// 测试分页查询 @Test public void testPage() { //第一个参数代表当前页 //第二个参数代表每页显示的数据条数 Page<User> page=new Page<>(1,5); userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); }
这里Page有三个构造函数的如下图:
无参构造函数默认情况下就是显示第一页,每页显示的数据条数默认是10条
测试代码:
Page<User> page=new Page<>();
我们可以看到在执行分页查询之前,它先查询了数据的总条数,之后再执行的分页查询,并且可以看到显示的也的确是第一页的10条数据
之后我们测试第二种构造函数
Page<User> page=new Page<>(2,5);
可以看到整体流程也是和上面差不多,只是显示的数据条数和第几页发生了变化.
我们再测试一下第三种构造函数
Page<User> page=new Page<>(2,5,6);
显然分页查询仍然能够正常执行下去的,但是我们可以发现他是 直接执行分页查询操作 ,并没有像上面两步一样先去执行一次查询数据总量的操作,这就是因为我们已经给定了total这个变量名了,所以他就不会再去执行这个操作了,并且我们不需要一定给定正确的total值,只要随便给定一个了,很明显我们一共是有11条数据的,但是我输入6,他也是能够正常执行出来的.













