1首先说下引入
pom里面添加:
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>yml添加:
# 数据源
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
创建包 mapper 编写Mapper 接口:
public interface UserMapper extends BaseMapper<User> {
...........
}
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
例如:
@SpringBootApplication
@MapperScan("com.zx.mapper")
public class MybatisPlusApplication {
......
}
2MP的主键策略
1、ASSIGN_ID
MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)
- 雪花算法:分布式ID生成器
- 雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
- 核心思想:
- 长度共64bit(一个long型)。
- 首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
- 41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
- 10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
- 12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。
小项目我们用自增
AUTO 自增策略
- 需要在创建数据表的时候设置主键自增
- 实体字段中配置 @TableId(type = IdType.AUTO)
3自动填充
实体上增加字段并添加自动填充注解
@Data
public class User {
......
@TableField(fill = FieldFill.INSERT)
private Date createTime; //@TableField(fill = FieldFill.UPDATE)
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}实现MetaObjectHandler接口 重写 insertFill 和 updateFill 不要忘记@Component | 这里的数据库是datetime类型 然后在实体类里面写 Date类型
package com.zx
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler { @Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
} @Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
4乐观锁
1、场景
一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1多万。
2、乐观锁与悲观锁
- 上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。
- 如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。
乐观锁实现流程
(1)修改实体类
添加 @Version 注解
@Version
private Integer version;
(2)创建配置文件
创建包config,创建文件MybatisPlusConfig.java
@MapperScan 扫描注解
package com.zx.config;
@EnableTransactionManagement
@Configuration
@MapperScan("com.zx.mapper")
public class MybatisPlusConfig {
}
(3)注册乐观锁插件
在 MybatisPlusConfig 中注册 Bean
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
5查询
通过多个id批量查询
@Test
public void testSelectBatchIds(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
简单的条件查询
通过map封装查询条件
注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id
@Test
public void testSelectByMap(){ HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println);
}
6分页
分页插件
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
(1)添加分页插件
配置类中添加@Bean配置
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
(2)selectPage实现分页
@Test
public void testSelectPage() { Page<User> page = new Page<>(1,5);
Page<User> pageParam = userMapper.selectPage(page, null); pageParam.getRecords().forEach(System.out::println);
System.out.println(pageParam.getCurrent());
System.out.println(pageParam.getPages());
System.out.println(pageParam.getSize());
System.out.println(pageParam.getTotal());
System.out.println(pageParam.hasNext());
System.out.println(pageParam.hasPrevious());
}
返回指定列
Page<Map<String, Object>> page = new Page<>(1, 5);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name", "age");
Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, queryWrapper); List<Map<String, Object>> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println(pageParam.getCurrent());
System.out.println(pageParam.getPages());
System.out.println(pageParam.getSize());
System.out.println(pageParam.getTotal());
System.out.println(pageParam.hasNext());
System.out.println(pageParam.hasPrevious());
7删除
逻辑删除
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
1 添加 deleted字段
2 添加deleted 字段,并加上 @TableLogic 注解
@TableLogic
private Integer deleted;
3配置(可选)application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
根据id删除记录
@Test
public void testDeleteById(){ int result = userMapper.deleteById(5L);
System.out.println(result);
}
批量删除
@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
System.out.println(result);
}
简单条件删除
@Test
public void testDeleteByMap() { HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);deleteByMap(map);
System.out.println(result);
}
8条件构造器
一、wapper介绍
@Test
public void testSelectOne() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "张旭"); User user = userMapper.selectOne(queryWrapper);//只能返回一条记录,多余一条则抛出异常
System.out.println(user);
}
3、between、notBetween
@Test
public void testSelectCount() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.between("age", 20, 30); Integer count = userMapper.selectCount(queryWrapper); //返回数据数量
System.out.println(count);
}
4、like、notLike、likeLeft、likeRight
selectMaps()返回Map集合列表,通常配合select()使用
@Test
public void testSelectMaps() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper
.select("name", "age")
.like("name", "e")
.likeRight("email", "5"); List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
maps.forEach(System.out::println);
}
5、in、notIn、inSql、notinSql、exists、notExists
in、notIn:
• notIn("age",{1,2,3})--->age not in (1,2,3)
• notIn("age", 1, 2, 3)--->age not in (1,2,3)
inSql、notinSql:可以实现子查询
• 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6)
• 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
@Test
public void testSelectObjs() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// queryWrapper.in("id", 1, 2, 3);
queryWrapper.inSql("id", "select id from user where id <= 3"); List<Object> objects = userMapper.selectObjs(queryWrapper);//返回值是Object列表
objects.forEach(System.out::println);
}
6、or、and
注意:这里使用的是 UpdateWrapper
不调用or
则默认为使用 and
连接
@Test
public void testUpdate1() { //修改值
User user = new User();
user.setAge(99);
user.setName("Andy"); //修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "h")
.or()
.between("age", 20, 30); int result = userMapper.update(user, userUpdateWrapper);
System.out.println(result);
}
7、lambda表达式
lambda表达式内的逻辑优先运算
@Test
public void testUpdate2() { //修改值
User user = new User();
user.setAge(99);
user.setName("Andy"); //修改条件
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper
.like("name", "n")
.or(i -> i.like("name", "a").eq("age", 20)); int result = userMapper.update(user, userUpdateWrapper);
System.out.println(result);
}
8、orderBy、orderByDesc、orderByAsc
@Test
public void testSelectListOrderBy() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age", "id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
9、set、setSql
最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中 的字段
@Test public void testUpdateSet() { //修改值 User user = new User(); user.setAge(60); //修改条件 UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper .like("name", "h") .set("name", "Peter")//除了可以查询还可以使用set设置修改的字段 .setSql(" email = '123@qq.com'");//可以有子查询 int result = userMapper.update(user, userUpdateWrapper); }