学习笔记-mybatis-plus
概述
官网:MyBatis-Plus (baomidou.com)
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
快速开始
新建springboot web项目
导入依赖:尽量不要同时导入mybatis 和mybatis-plus
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mybatis-plus--->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
配置连接数据库:
# DataSource Config
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#schema: classpath:db/schema-h2.sql
#data: classpath:db/data-h2.sql
url: jdbc:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: yang
password: 123456
编写实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
编写mapper接口~~~~
@Repository // 代表持久层
//在对应的mapper接口上继承接:BaseMapper 并传入泛型
public interface UserMapper extends BaseMapper<User> {
}
开启mapper扫描 @MapperScan
@MapperScan("com.yang.mapper")//扫描mapper文件夹
@SpringBootApplication
public class SpringbootMybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisplusApplication.class, args);
}
}
测试:
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
配置日志
插入测试
User user = new User();
user.setAge(3);
user.setEmail("134679262@qq.com");
user.setName("123");
int insert = userMapper.insert(user);
System.out.println(insert);
插入成功,发现自动生成id!!(要求表名与实体类名一致)
主键生成策略
雪花生成算法:(默认)
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是︰使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一! I
其他策略: @TableId
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
- AUTO 主键自增 需要数据库设置自增
- NONE 未设置主键
- INPUT 手动输入
更新测试
@Test
void testUpdate(){
User user = new User();
user.setId(3L);
user.setAge(5);
int update = userMapper.updateById(user);
System.out.println(update);
}
sql根据参数动态配置~~
自动填充
数据库级别(不建议)
)
并在实体类中同步
private Date creat_time;
private Date update_time;
代码级别
去掉默认值
在实体类的属性上设置 @TableField
@TableField(fill = FieldFill.INSERT) //插入时填充
private Date creat_time;
@TableField(fill = FieldFill.UPDATE) //更新时填充
private Date update_time;
自定义填充策略
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill....");
this.setFieldValByName("creat_time",new Date(),metaObject);
this.setFieldValByName("update_time",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill....");
this.setFieldValByName("update_time",new Date(),metaObject);
}
}
乐观锁
乐观锁:故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!|
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时携带version
- 执行更新操作时,version= new_verison where version = old_version
- version 不匹配时,更新失败
测试
增加version字段
配置version属性 @Version MP的注解
@Version
private Integer version;
注册组件:
@Configuration
//@EnableTransactionManagement ???官网没有
@MapperScan("com.yang.mapper")
public class MybatisPlusConfig {
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试:
- 成功
@Test
void test1(){
User user = userMapper.selectById(1487730131458940930L);
user.setAge(5);
user.setName("啊啊啊啊");
int update = userMapper.updateById(user);
}
先取出后更新,会比较version,成功后version+1
- 失败
@Test
void test2(){
User user = userMapper.selectById(1487730131458940930L);
user.setAge(5);
user.setName("哈哈哈哈");
//模拟多线程被插队
User user2 = userMapper.selectById(1487730131458940930L);
user2.setAge(5);
user2.setName("1111");
int update2 = userMapper.updateById(user2);
int update = userMapper.updateById(user);
}
在没有乐观锁时,这条数据会被 “ 哈哈哈哈 ” 覆盖,但在乐观锁作用下,后面的更新语句失败了
注意:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
查询
多Id查询
@Test
void testquery(){
List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
for (User user : userList) {
System.out.println(user);
}
}
map条件查询 不能实现模糊查询
@Test
void testquery1(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","1111");
List<User> userList = userMapper.selectByMap(map);
for (User user : userList) {
System.out.println(user);
}
}
分页查询
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
使用:
@Test
void testpage(){
Page<User> page = new Page<>(1,3); //第几页,页面大小
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
}
逻辑删除
物理删除:从数据库中删除
逻辑删除:还在数据库中,通过一个变量来使其失效,防止数据丢失
@TableLogic //逻辑删除
private Integer deleted;
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)
实际走的是更新操作,之后查询时会自动拼接 deleted=0 的查询条件,仅查询逻辑未删除的列
性能分析插件?????
生产环境不要用
该功能依赖 p6spy
组件,完美的输出打印 SQL 及执行时长
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>最新版本</version>
</dependency>
- application.yml 修改:
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
-
spy.properties 配置:
driverlist=com.mysql.cj.jdbc.Driver logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat #logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat databaseDialectDateFormat=yyyy-MM-dd HH:mm:ss appender=com.p6spy.engine.spy.appender.StdoutLogger
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
条件构造器
- isNotNull ge
@Test
void test1(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",18); // name、email不为空且age>=18
userMapper.selectList(wrapper).forEach(System.out::println);
}
- eq
@Test
void test2(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","1111");
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
- between
@Test
void test3(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",18,23);
Long aLong = userMapper.selectCount(wrapper);
System.out.println(aLong);
}
- notLike likeLeft
@Test
void test4(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notLike("name","J")
.likeLeft("name","3"); // %3
userMapper.selectMaps(wrapper).forEach(System.out::println);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)