Mybatis-Plus学习笔记
特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
环境搭建所需要的依赖:
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
然后在spring boot配置文件中配置好数据源以及mybatis-plus配置:
如:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注意:导入mybatis-Plus后不要在导入任何的mybatis以来了
应用:
创建与数据库表中相对性的JavaBean实体对象,如果表中字段带有下划线例如user_name,对象属性以驼峰形式来接,mybatis-plus,会自动进行匹配。
编写对应的mapper接口,要继承BaseMapper<T>,这个类中已经实现了我们常用的CRUD操作,只调用即可,而且也不用再写相对应的对象Mapper.xml了,Sql语句我们也不用管理了,下面是BaseMapper<T>中一些方法的使用:
1.测试查询:
@Test
public void selectTest(){
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
//查询案例:查询批量用户
@Test
public void testSelectBatchIds(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(21, 22, 23));
users.forEach(System.out::println);
}
//查询案例:按条件查询
@Test
public void testSelectBatchId(){
HashMap<String, Object> map = new HashMap<>();
map.put("name", "熊大");
map.put("age", 16);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
//分页查询
@Test
public void testPaginationInterceptor(){
Page<User> page = new Page<>(1,2);
userMapper.selectPage(page, null);
System.out.println(page.getTotal());
page.getRecords().forEach(System.out::println);
}
//查询案例:查询批量用户
@Test
public void testSelectBatchIds(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(21, 22, 23));
users.forEach(System.out::println);
}
注意再分页查询的时候,需要配置一个分页查询组件,一般会专门编写一个配置类来管理mybatis=plus所需要的组件:
@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.测试插入;
@Test
public void insertTest(){
User user = new User();
user.setAge(16);
user.setName("小明");
user.setEmail("13029228@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
}
3 .测试更新:需要添加乐观锁插件
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
乐观锁配置需要2步 记得两步
插件配置
1spring boot:
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
2.注解实体字段 @Version
必须要!
@Version
private Integer version;
特别说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
int id = 100;
int version = 2;
User u = new User();
u.setId(id);
u.setVersion(version);
u.setXXX(xxx);
if(userService.updateById(u)){
System.out.println("Update successfully");
}else{
System.out.println("Update failed due to modified by others");
}
示例SQL原理
update tbl_user set name = 'update',version = 3 where id = 100 and version = 2
4.删除(逻辑删除)
说明:
只对自动注入的sql起效:
- 插入: 不作限制
- 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
- 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
- 删除: 转变为 更新
例如:
- 删除:
update user set deleted=1 where id = 1 and deleted=0
- 查找:
select id,name,deleted from user where deleted=0
字段类型支持说明:
- 支持所有数据类型(推荐使用
Integer
,Boolean
,LocalDateTime
) - 如果数据库字段使用
datetime
,逻辑未删除值和已删除值支持配置为字符串null
,另一个值支持配置为函数来获取值如now()
附录:
- 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
- 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。
用法:
步骤1: 配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig
- 例: application.yml
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
步骤2: 实体类字段上加上@TableLogic
注解
@TableLogic
private Integer deleted;
另外;
QueryWrapper<User> wrapper = new QueryWrapper<>();能够对查询条件做一些筛选
用法:
//条件查询
@Test
void contextLoads() {
//查询name不为空并且邮箱也不为空,而且年龄大于等于10
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email");
wrapper.between("age", 12, 22);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
//模糊查询
@Test
void test(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//LikeRight 表示%在右边
wrapper.notLike("name", "熊") //%熊%
.likeRight("age", 1);//1%
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
//子查询
@Test
void test1(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from user where id>17");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}