赞
踩
目录:
官网:http://mp.baomidou.com/
参考教程:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper
mybatis-plus是一个mybatis的增强工具,在mybatis的基础上之作增强不做改变,为简化开发、提高效率而生。
使用步骤:
**1:**开始创建数据库(mybatis_plus),创建数据库表,添加数据,用于mp操作
数据表创建:
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
其对应的数据库Data脚本如下:那个user表中
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
**2:**创建一个springboot(2.3.0)工程(myplus)
**3:**添加springboot和mybatis-plus依赖
spring-boot-starter、spring-boot-starter-test:其内本身就有
添加:mybatis-plus-boot-starter、MySQL、lombok
lombok:不用写get和set方法,只需要添加个注解就行
不过这玩意还是有点麻烦,可以自动创建springboot,进行勾选,即可以省去这一步骤
<!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--用lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
**4:**安装lombok插件
IDEA–File–setting–Plugins–输入lombok–下载–重启IDEA
**5:**创建application.properties,并作配置(当然,yml配置文件也可以)
当然,springboot中,其本来是有的。在其内添加:(mysql数据库连接)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimeZone=GMT%2BB
spring.datasource.username=root
spring.datasource.password=123456
注:这是2.1以后版本所用,添加了:cj serverTimezone=GMT%2BB(时区)
**6:**创建类,编写代码
在main的那com…下面创建一个entity的包,用来存放实体类;创建一个mapper的包,这是mybatis-plus中的。
在entity包创建一个实体类User,添加:
@Data //不用添加get and set和toString方法了
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
在mapper下建立UserMapper接口,且让其继承自BaseMapper:这样就可以调用BaseMapper中的增删改查方法,不用再弄xml。:使其都为User类中的类型
package com.zpc.myplus.mapper;
@Repository //用来声明对象,来使测试的时候不报错
public interface UserMapper extends BaseMapper<User> {
}
在springboot的那个主文件中,添加: 以此来使主程序找到mapper这个接口
@MapperScan("com.zpc.myplus.mapper")
其主文件:
package com.zpc.myplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @MapperScan("com.zpc.myplus.mapper") @SpringBootApplication //springboot启动类 public class MyplusApplication { public static void main(String[] args) { SpringApplication.run(MyplusApplication.class, args); } }
7:测试
接下来,在测试类(test下的)测试下: (不用在程序中写此代码,这是为了测试)
@Autowired //将其注入
private UserMapper userMapper; //用来调用UserMapper中的方法
//查询user表中的所有属性
@Test
public void findAll() {
List<User> users = userMapper.selectList(null);
//先输入userMapper.,后面会出现一系列方法,由于此方法返回的是List集合,且其内有参数,故给参数赋值null,再在其后”.var“,让其返回所有东西
System.out.println(users);
即可查出
注:查看sql输出日志,更直观化的查看数据库中的内容
在配置文件
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
当然,其id是默认配置的,下节说id问题
userMapper.insert返回的是一个user,故而在之前实例化user,再对其添加
//添加操作
@Test
public void addUser(){
User user=new User();
user.setName("名");
user.setAge(11);
user.setEmail("122@qq.com");
int insert = userMapper.insert(user);
System.out.println("s" +insert);
}
参考资料:https://www.cnblogs.com/haoxinyue/p/5208136.html
主动策略:
1:自动增长,AUTO INCREMENT
1-10000 10001-20000 20001-30000
缺点:分表分库时会比较麻烦。比如,下一张表id需要再上一个最后一个id的基础上加一
2:UUID
每次生成随机唯一的值
缺点:排序不方便
3:redis生成id
可以使用Redis集群来获取更高的吞吐量。假如一个集群中有5台Redis。可以初始化每台Redis的值分别是1,2,3,4,5,然后步长都是5。各个Redis生成的ID为:
A:1,6,11,16,21
B:2,7,12,17,22
C:3,8,13,18,23
D:4,9,14,19,24
E:5,10,15,20,25
缺点:1)如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。
2)需要编码和配置的工作量比较大。
4:mp自带策略(默认策略)(Twitter的snowflake算法)
生成一个19位的值
snowflake(雪花)是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。
在主键id上方加:
@TableId(type = IdType.AUTO)
private Long id;
注:那个点后面:
AUTO:自动增长
ID_WORKER:mp自带策略,生成19位值,数字类型使用这种策略,比如long(说的是主键的)
ID_WORKER_STR: mp自带策略,生成19位值,字符串类型使用这种策略,比如String(说的是主键的)
INPUT:设置ID值
NONE:输入
UUID:随即唯一值
配置实体类中相关字段的自动填充策略,在@TableField注解中设置fill属性
DEFAULT:默认不处理
INSERT:插入填充字段
UPDATE:更新填充字段
INSERT_UPDATE:插入和更新填充字段
修改操作
//修改操作
@Test
public void updateUser(){
User user=new User();
user.setId(2L); //根据id改,其主键id是long类型
user.setAge(100);
int i = userMapper.updateById(user);
System.out.println(i);
}
这样的修改只是弄了要修改的,比如只是修改了id为2对应的年龄,但其对应的其他的却没有修改。故而,就有了自动填充!
运行结果 如:
==> Preparing: UPDATE user SET age=? WHERE id=?
> Parameters: 100(Integer), 2(Long)
< Updates: 1
自动填充
1:先给数据表添加两个字段:create_time (创建时间) update_time (更新时间),其类型都选datetime
2:添加实体类属性:User
驼峰命名法
private Data createTime; //create_time
private Data updateTime; //update_time
现在,更改上一次添加的数据,运行后,就会发现,create_time和update_time还是null,借此,就说到了mp的自动填充:不需要set到对象里面值,使用mp方式实现数据添加
如:以前mybatis的:手动添加
//添加操作
@Test
public void addUser(){
User user=new User();
user.setName("tian");
user.setAge(14);
user.setEmail("1223@qq.com");
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
int insert = userMapper.insert(user);
System.out.println("s" +insert);
}
自动填充:
第一步:在实体类里面进行自动填充属性添加注解
@TableField(fill = FieldFill.INSERT) //INSERT添加
private Data createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) //INSERT_UPDATE添加和修改的时候里面都有值
private Data updateTime;
第二步:先随便创建个包(这个随意),创建类,实现接口 MetaObjectHandler,实现接口里面的方法.
@Component //表示交给spring去管理 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); } }
解决丢失更新问题(当要更新一条记录的时候,希望这条记录没有被别人更新)
丢失更新(多个人同时去修改同一条记录,最后提交的那个,会把之前提交的都给覆盖掉)
问题解决:悲观锁(串行):同一个东西,只能一个人同时操作
乐观锁:取出记录时,获取当前version(版本号)
更新时,带上这个version(更新完成后,版本号会变化)
执行更新时,set version=newVersion where version=oldVersion
如果version不对,就更新失败
1:在表里面加一个version(int型),意为版本号
2:对应实体类(User)添加版本号属性
在实体类版本号属性上添加注解
@Version
private Integer version;//版本号
3:配置乐观锁插件
一:如果是spring xml:添加这即可
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
二:如果是spring boot:
@Bean //插件
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
注:建立一个配置类(存放所有的配置):
先创建个包config(存储所有的配置类),再创建mp的配置类:MpConfig
添加一个@Configuration,再把配置放进去。再把启动类中的中的@MapperScan(“com.zpc.myplus02.mapper”)添加过来
注:只要是属于mp的配置,皆可放在这里
package com.zpc.myplus02.config;
//包省略
@Configuration
@MapperScan("com.zpc.myplus02.mapper") //以此来使主程序找到mapper这个接口
public class MpConfig {
//配置乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4:这步在开发中可省略(这玩意是为理解)
给version一个初始值,先在实体类User中
@TableField( fill = FieldFill.INSERT) //INSERT添加
@Version
private Integer version;//版本号
再在MyMetaObjectHandler,的那个insertFill方法中,添加一个自动填充,让其初始值为1
this.setFieldValByName("updateTime",1,metaObject);
1:根据id查询
User user=userMapper.selectById(123442)
2:多个Id查询
//多个id查询
@Test
public void moreid(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
System.out.println(users);
}
1:放插件,放入MpConfig
@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:在测试类中
编写分页代码,new page对象,传入两个参数(当前页和每页显示记录数),调用mp方法实现分页查询
//分页查询 @Test public void testPage(){ //new page,传入当前页和每页显示记录数 Page<User> page=new Page<>(1,3); //把分页所有数据封装到page对象中 userMapper.selectPage(page,null); System.out.println(page.getCurrent()); //当前页 System.out.println(page.getRecords()); //每页数据list集合 System.out.println(page.getSize()); //每页数据记录数 System.out.println(page.getTotal()); //总记录数 System.out.println(page.getPages()); //总页数 System.out.println(page.hasNext()); //是否存在下一页 System.out.println(page.hasPrevious()); //是否存在上一页 }
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改成"被删除状态"(deleted值就为1),之后在数据库中仍旧能看到此条数据记录
1:根据id删除(物理删除)
@Test //物理删除
public void testDeleteById(){
int result=userMapper.deleteById(3L);
System.out.println(result);
}
2:批量删除()
@Test
public void testDeleteBatchIds(){
int result=userMapper.deleteBatchIds(Arrays.asList(1,2,3));
System.out.println(result);
}
表中数据看起来还在,不过查询查不出来
1:给表中添加字段deleted(tinyint类型),并将其默认值(Default)填为0
再在实体类中添加属性,并附上注解
@TableLogic
private Integer deleted;//逻辑删除的值
如果每有设置默认值,那就在MyMetaObjectHandler,的那个insertFill方法中,添加一个自动填充,让其初始值为0
//添加逻辑删除的默认值0
this.setFieldValByName("deleted",0,metaObject);
2:配置逻辑删除插件,在mpconfig
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
3:在配置文件中加入(可以不加,因为这是默认的)
即代表,删除时值(Default)为1,不删除时值为0
mabatis-plus.global-config.db-config.logic-delete-value=1
mabatis-plus.global-config.db-config.logic-not-delete-value=0
4:在测试文件中,还是用物理删除的那个,不过其效果已经变成了逻辑删除
@Test
public void testDeleteById(){
int result=userMapper.deleteById(3L);
System.out.println(result);
}
性能分析拦截器,用于输出每条SQL语句及其执行时间
SQL性能分析,开发环境使用,超过指定时间,停止运行。有助于发现问题
1:在配置类中mpconfig
注:三种环境:dev:开发环境
test:测试环境
prod:生产环境(结束后加)
/*
*SQL执行性能分析插件
*开发环境使用,线上不推荐。maxTime指的是sql最大执行时长
*/
@Bean
@Profile({"dev","test"}) //设置dev test环境开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100); //ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
2:spring boot中设置dev环境
#环境设置:dev、test、prod
spring.profiles.active=dev
执行查询后,如果时间超过设置的那个时间,就会报错,且不执行其
mp中实现条件查询,一般都使用QueryWrapper
步骤:创建QueryWrapper对象
调用里面的方法实现各种查询(https://mp.baomidou.com/guide/wrapper.html#abstractwrapper)
注:这只是一部分,具体可在上方官网查询
ge(大于等于)eq(等于)ne(不等于)gt(大于)lt(小于)le(小于等于)
@Test
public void testSelectQuery(){
//创建QueryWrapper对象
QueryWrapper<User> wrapper=new QueryWrapper<>();
//查询age>=30记录
wrapper.ge("age",30);
List<User> users=userMapper.selectList(wrapper);
System.out.println(users);
}
between(BETWEEN 值1 AND 值2):范围
@Test
public void testSelectQuery(){
//创建QueryWrapper对象
QueryWrapper<User> wrapper=new QueryWrapper<>();
//查询age在30到40之间记录
wrapper.beteen("age",30,40);
List<User> users=userMapper.selectList(wrapper);
System.out.println(users);
}
like(模糊查询)
//查询名字中包含于的
wrapper.like("NAME","于");
orderByDesc/Asc(排序)
last(直接拼接到sql的最后)
wrapper.last("limit 1");
select(指定要查询的列)
//只会查出来id和name
wrapper.select("id","name")
List<User> users=userMapper.selectList(wrapper);
System.out.println(users);
}
between(BETWEEN 值1 AND 值2):范围
```java
@Test
public void testSelectQuery(){
//创建QueryWrapper对象
QueryWrapper<User> wrapper=new QueryWrapper<>();
//查询age在30到40之间记录
wrapper.beteen("age",30,40);
List<User> users=userMapper.selectList(wrapper);
System.out.println(users);
}
like(模糊查询)
//查询名字中包含于的
wrapper.like("NAME","于");
orderByDesc/Asc(排序)
last(直接拼接到sql的最后)
wrapper.last("limit 1");
select(指定要查询的列)
//只会查出来id和name
wrapper.select("id","name")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。