本项目是一个在线教育项目,采用前后端分离技术,技术栈如下:
- 前端: Vue、Element-ui、Axios、Node.js …
- 后端:SpringBoot、SpringCloud、Mybatis-Plus、SpringSecurity、Redis、Maven、EasyExcel、JWT、OAuth2 …
- 其他:阿里云OSS、阿里云视频点播服务、腾讯云短信服务、微信登录和支付、Docker、Git、Jenkins、Nginx …
今天主要复习Mybatis-Plus(MP),因为持久层技术是本项目的重点之一。
创建数据库表
DROP TABLE IF EXISTS `user`;
create table user
(
id bigint auto_increment comment '主键ID' primary key,
name varchar(30) null comment '姓名',
age int null comment '年龄',
email varchar(50) null comment '邮箱',
create_time datetime null comment '创建时间',
update_time datetime null comment '修改时间',
version int null comment '版本(测试乐观锁)'
);
新建SpringBoot工程并引入依赖、编写配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MP依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
<!-- MySql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus1?serverTimezone=GMT%2B8
username: root
password: root
# 查看sql执行过程
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
entity、mapper
@Data
public class User {
// 主键生成策略:自增
@TableId(type = IdType.AUTO)
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;
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
}
@Mapper // 不加该注解在测试类的@Autowired中会报错
public interface UserMapper extends BaseMapper<User> {
}
Mybatis-Plus测试
查询所有数据
@Autowired private UserMapper userMapper; // 查询user表中的所有数据 @Test void contextLoads() { List<User> users = userMapper.selectList(null); System.out.println(users); }
添加数据
// mp实现添加操作 @Test void addUser() User user = new User(); user.setName("Prannt"); user.setAge(12); user.setEmail("prannt@qq.com"); int insert = userMapper.insert(user); System.out.println("insert = " + insert
修改数据
// update @Test void updateUser() User user = new User(); user.setId(1461239461974220801L); user.setAge(130); int row = userMapper.updateById(user); System.out.println(row); }
测试乐观锁
在实体类的字段上添加注解
@Version @TableField(fill = FieldFill.INSERT) private Integer version;
配置乐观锁插件
package com.atguigu.mpdemo1010.config; @Configuration @MapperScan("com.atguigu.mpdemo1010.mapper") // 扫描到mapper接口所在的包 public class MpConfig { // 配置乐观锁插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
给version字段添加初始值
package com.atguigu.mpdemo1010.handler; @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 为版本号添加初始值 this.setFieldValByName("version",1,metaObject); } }
测试
@Test void testOptimisticLocker(){ // 先查再改 // 根据id查询数据 User user = userMapper.selectById(1461239461974220804l); // 修改查查来的这条数据 user.setAge(200); userMapper.updateById(user); // 每修改一次,version +1,因为我已经修改3次了,所以version为3 }
结果
多个id批量删除(用的不多)
@Test public void testSelectDemo1(){ List<User> list = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L)); System.out.println(list); // 因为数据库中只有id = 1的记录,所以只返回一条记录 }
分页查询(用的多)
配置分页插件
@Configuration @MapperScan("com.atguigu.mpdemo1010.mapper") public class MpConfig { // 配置分页插件 @Bean public MybatisPlusInterceptor page() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; } }
编写分页代码
@Test void testPage() // 1.创建page对象 // 传入两个参数:当前页和每页显示记录数 Page<User> page = new Page<>(1,3); // 2.分页查询 userMapper.selectPage(page,null); // 通过page对象获取分页数据 System.out.println(page.getCurrent()); // 当前页 1 System.out.println(page.getRecords()); // 每页数据的list集合 System.out.println(page.getSize()); // 每页显示的记录数 3 System.out.println(page.getTotal()); // 总记录数 8 System.out.println(page.getPages()); // 一共有多少页 3 System.out.println(page.hasNext()); // 是否有下一页 true System.out.println(page.hasPrevious()); // 是否有上一页 false }
物理删除、逻辑删除
物理删除:从硬盘中删除数据,删掉就真的从数据库里消失了
// 物理删除 @Test public void testDeleteById() // 根据id查询数据 User user = userMapper.selectById(1461239461974220809l); int res = userMapper.deleteById(1461239461974220809l); System.out.println(res); }
逻辑删除:数据库中的字段
deleted
表示是否删除(删除之后记录还存在于数据库中,但是deleted字段变为1)// 1.在数据库表中添加逻辑删除的字段,对应实体类添加属性 @TableLogic private Integer delete;
# 2.在实体类上加注解 mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0
// 3.测试 @Test void testDeleteBatchIds() int res = userMapper.deleteBatchIds(Arrays.asList(2,3,4)); System.out.println(res); }
测试结果
复杂条件查询
// MybatisPlus实现复杂条件查询 @Test void testSelectQuery() // 创建QueryWrapper对象 QueryWrapper<User> wrapper = new QueryWrapper<>(); // 通过QueryWrapper设置条件 // ge/gt/le/lt // 查询age >= 30的记录 wrapper.ge("age",30); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // eq/ne wrapper.eq("name","Lucy"); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // between // 年龄在20-30范围 wrapper.between("age",20,30); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // like wrapper.like("name","n"); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // orderByDesc wrapper.orderByDesc("id"); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // last wrapper.last("limit 3"); List<User> users = userMapper.selectList(wrapper); System.out.println(users); // 指定要查询的列 wrapper.select("id","name"); List<User> users = userMapper.selectList(wrapper); System.out.println(users); }
自动填充
在相关实体上添加注解
@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
配置handler
@Component public class MyMetaObjectHandler implements MetaObjectHandler { // 使用mp实现添加操作,该方法会执行 @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("createTime",new Date(),metaObject); // 根据名称设置属性值 this.setFieldValByName("updateTime",new Date(),metaObject); } // 使用mp实现修改操作,该方法会执行 @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime",new Date(),metaObject); } }