1、分页插件 a>添加配置类MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
官网地址:插件主体 | MyBatis-Plus (baomidou.com)
创建 MybatisPlusConfig,路径在src/main/java/com/mybatisplus_demo/config/MybatisPlusConfig.java
同时将将主类MyBatisPlusDemoApplication中的注解移到此处
@Configuration
@MapperScan("com.mybatisplus_demo.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
b>测试
本节测试,全部采用Mapper CURD;创建测试类,路径为:src/test/java/com/mybatisplus_demo/MyBatisPlusPluginsTest.java
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyBatisPlusPluginsTest {
@Autowired(required = false)
private UserMapper userMapper;
@Test
public void testPage() {
// limit index,size
// index=(current-1)*size
Page page = new Page<>(2, 3); // 设置当前页和每页显示条数
userMapper.selectPage(page, null); // 对所有数据进行分页
//获取分页数据
List list = page.getRecords();
list.forEach(System.out::println);
System.out.println("当前页:" + page.getCurrent());
System.out.println("每页显示的条数:" + page.getSize());
System.out.println("总记录数:" + page.getTotal());
System.out.println("总页数:" + page.getPages());
System.out.println("是否有上一页:" + page.hasPrevious());
System.out.println("是否有下一页:" + page.hasNext());
}
}
2、xml自定义分页
a>UserMapper中定义接口方法
路径为src/main/java/com/mybatisplus_demo/mapper/UserMapper.java
Pageb>UserMapper.xml中编写SQLselectPageVo(@Param("page") Page page, @Param("age") Integer age);
路径为src/main/resources/mapper/UserMapper.xml
c>配置类型别名在application.yml中配置,路径为src/main/resources/application.yml
spring:
# 配置数据源信息
datasource:
# 配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库的各个信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis-plus:
configuration:
# 配置MyBatis-Plus的日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置MyBatis-Plus的全局配置
global-config:
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: t_
# 配置MyBatis-Plus的主键策略
id-type: auto
# 配置类型别名所对应的包
type-aliases-package: com.mybatisplus_demo.pojo
d>测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyBatisPlusPluginsTest {
@Autowired(required = false)
private UserMapper userMapper;
@Test
public void testSelectPageVo(){
Page page = new Page<>(1, 3); // 设置当前页和每页显示条数
userMapper.selectPageVo(page, 20);
//获取分页数据
List list = page.getRecords();
list.forEach(System.out::println);
System.out.println("当前页:" + page.getCurrent());
System.out.println("每页显示的条数:" + page.getSize());
System.out.println("总记录数:" + page.getTotal());
System.out.println("总页数:" + page.getPages());
System.out.println("是否有上一页:" + page.hasPrevious());
System.out.println("是否有下一页:" + page.hasNext());
}
}
3、乐观锁 a>场景此处只是演示自定义分页,也可以直接使用userMapper.selectPage()方法:
LambdaQueryWrapperqueryWrapper = new LambdaQueryWrapper<>(); queryWrapper.ge(User::getAge, 20); userMapper.selectPage(page, queryWrapper); // 对查询条件进行分页
b>乐观锁与悲观锁一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小 李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王 也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就 完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1万多。
c>模拟修改冲突 数据库中增加商品表上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过 了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。
如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证 最终的价格是120元。
CREATE TABLE t_product ( id BIGINT(20) NOT NULL COMMENT '主键ID', NAME VARCHAr(30) NULL DEFAULT NULL COMMENT '商品名称', price INT(11) DEFAULT 0 COMMENT '价格', VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id) );添加数据
INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人笔记本', 100);添加实体
路径为src/main/java/com/mybatisplus_demo/pojo/User.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id;
private String name;
private Integer price;
private Integer version;
}
添加mapper
路径为src/main/java/com/mybatisplus_demo/mapper/ProductMapper.java
public interface ProductMapper extends BaseMapper测试{ }
路径为src/test/java/com/mybatisplus_demo/MyBatisPlusPluginsTest.java
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyBatisPlusPluginsTest {
@Autowired(required = false)
private ProductMapper productMapper;
@Test
public void testConcurrentUpdate(){
//1、小李查询商品价格
Product p1 = productMapper.selectById(1L);
System.out.println("小李取出的商品价格:" + p1.getPrice());
//2、小王查询商品价格
Product p2 = productMapper.selectById(1L);
System.out.println("小王取出的商品价格:" + p2.getPrice());
//3、小李将价格加了50元,存入了数据库
p1.setPrice(p1.getPrice() + 50);
int i = productMapper.updateById(p1);
System.out.println("小李更新了商品价格:" + i);
//4、小王将商品减了30元,存入了数据库
p2.setPrice(p2.getPrice() - 30);
int j = productMapper.updateById(p2);
System.out.println("小王更新了商品价格:" + j);
//最后的结果
Product p3 = productMapper.selectById(1L);
//价格覆盖,最后的结果:70
System.out.println("最后的商品价格:" + p3.getPrice());
}
}
运行结果:
数据库中添加version字段,取出记录时,获取当前version
SELECT id,name,price,version FROM product WHERe id=1
更新时,version + 1,如果where语句中的version版本不对,则更新失败
UPDATE product SET price=price+50, version=version + 1 WHERe id=1 AND version=1e>Mybatis-Plus实现乐观锁 修改实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id;
private String name;
private Integer price;
@Version //标识乐观锁版本号字段
private Integer version;
}
添加乐观锁插件配置
在MybatisPlusConfig配置类中添加
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
测试
为方便测试,重新将t_product表中的id=1的price设置为100,重新运行如下:
修改测试方法,如下:
@Test
public void testConcurrentUpdate(){
//1、小李查询商品价格
Product p1 = productMapper.selectById(1L);
System.out.println("小李取出的商品价格:" + p1.getPrice());
//2、小王查询商品价格
Product p2 = productMapper.selectById(1L);
System.out.println("小王取出的商品价格:" + p2.getPrice());
//3、小李将价格加了50元,存入了数据库
p1.setPrice(p1.getPrice() + 50);
int i = productMapper.updateById(p1);
System.out.println("小李更新了商品价格:" + i);
//4、小王将商品减了30元,存入了数据库
p2.setPrice(p2.getPrice() - 30);
int j = productMapper.updateById(p2);
System.out.println("小王更新了商品价格:" + j);
if(j == 0){ // 可以考虑改用while
// 如果更新失败,则重试
p2= productMapper.selectById(1L);
p2.setPrice(p2.getPrice() - 30);
j = productMapper.updateById(p2);
}
System.out.println("小王更新(重新)了商品价格:" + j);
//最后的结果
Product p3 = productMapper.selectById(1L);
//价格覆盖,最后的结果:70
System.out.println("最后的商品价格:" + p3.getPrice());
}
测试
为方便测试,重新将t_product表中的id=1的price设置为100,version设置为0,重新运行如下:



