2, mybatisPlus学习
来源于蚂蚁课堂
1.Mybatis-plus与mybatis区别
2.BaseMapper接口实现快速增删改查
3.实现复杂的QueryWrapper条件构造器
4.mybatis-plus实现逻辑删除
5.mybatis-plus整合分页插件
6.mybatis-plus代码自动生成器
7.mybatis-plus动态切换数据源
8.mybatis-plus生成全局的主键id
9.mybatis-plus乐观锁的机制
mybatisPlus介绍
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生,和hibernate、jpa注解方式非常相似。
mybatisPlus特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持数据库
mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver
达梦数据库 、 虚谷数据库 、 人大金仓数据库
SpringBoot整合mybatisPlus
初始化表结构
CREATE TABLE `meite_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) DEFAULT NULL,
`user_age` int(10) DEFAULT NULL,
`user_addres` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`deleted` int(1) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of meite_user
-- ----------------------------
INSERT INTO `meite_user` VALUES ('27', 'zhangsan', '18', '湖北省武汉市', '2020-05-27 15:45:44', '0');
INSERT INTO `meite_user` VALUES ('29', 'yushengjun', '22', '湖北省孝感市', '2020-06-25 15:45:48', '0');
INSERT INTO `meite_user` VALUES ('30', '1', '19', '上海市', '2020-04-22 15:45:52', '1');
Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.taotao</groupId>
<artifactId>mybatis-plus1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
实体:
package com.taotao.mybatisplus1.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
*
* </p>
*
* @author jobob
* @since 2020-06-09
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class MeiteUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "user_id", type = IdType.AUTO)
private Integer userId;
private String userName;
private Integer userAge;
private String userAddres;
private LocalDateTime createTime;
/**
* 逻辑删除
* 0存在 1 隐藏
*/
@TableLogic
private Integer deleted = 0;
// 版本
@Version
private Integer version;
}
mapper:
package com.taotao.mybatisplus1.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.taotao.mybatisplus1.entity.MeiteUser;
/**
* <p>
* Mapper 接口
* </p>
*
* @author jobob
* @since 2020-06-09
*/
public interface MeiteUserMapper extends BaseMapper<MeiteUser> {
}
启动类:
package com.taotao.mybatisplus1;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.taotao.mybatisplus1.mapper")
@SpringBootApplication
public class MybatisPlus1Application {
public static void main(String[] args) {
SpringApplication.run(MybatisPlus1Application.class, args);
}
}
service:
package com.taotao.mybatisplus1.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.taotao.mybatisplus1.entity.MeiteUser;
import com.taotao.mybatisplus1.mapper.MeiteUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author jobob
* @since 2020-06-09
*/
@RestController
public class MeiteUserServiceImpl {
@Autowired
public MeiteUserMapper meiteUserMapper;
/**
* 根据id查询数据
* @param userId
* @return
*/
@GetMapping("/findByUser")
public MeiteUser findByUser(Integer userId) {
MeiteUser meiteUser = meiteUserMapper.selectById(userId);
return meiteUser;
}
/**
* 插入数据
* @param user
* @return
*/
@GetMapping("/insertUser")
public String insertUser(MeiteUser user) {
String result = meiteUserMapper.insert(user) > 0 ? "success" : "fail";
return result;
}
@GetMapping("/queryWrapper")
public List<MeiteUser> userList(MeiteUser user) {
QueryWrapper<MeiteUser> queryWrapper = new QueryWrapper<MeiteUser>();
String userName = user.getUserName();
//等于
/* if (!StringUtils.isEmpty(userName)) {
queryWrapper.eq("user_name", user.getUserName());
}*/
queryWrapper.eq(!StringUtils.isEmpty(user.getUserName()), "user_name", user.getUserName());
//大于
queryWrapper.gt(user.getUserAge() != null, "user_age", user.getUserAge());
//between
queryWrapper.between("user_age", 1, 34);
//like
queryWrapper.like(!StringUtils.isEmpty(user.getUserAddres()), "user_addres", user.getUserAddres());
//in
//orderbyDesc
queryWrapper.orderByDesc("create_time");
queryWrapper.orderByDesc("user_age");
List<MeiteUser> userList = meiteUserMapper.selectList(queryWrapper);
return userList;
}
/**
* 多条件修改
* @param user
* @return
*/
@GetMapping("/updateUserWrapper")
public String updateUserWrapper(MeiteUser user) {
UpdateWrapper<MeiteUser> userUpdateWrapper = new UpdateWrapper<>();
Integer userAge = user.getUserAge();
if (userAge != null) {
userUpdateWrapper.eq("user_age", userAge);
}
return meiteUserMapper.update(user, userUpdateWrapper) > 0 ? "success" : "fail";
}
/**
* 逻辑删除
* @param userId
* @return
*/
@GetMapping("/deleteById")
public String deleteById(Integer userId) {
return meiteUserMapper.deleteById(userId) > 0 ? "success" : "fail";
}
@GetMapping("/findByPageUserList")
public List<MeiteUser> findByPageUserList(Page page) {
QueryWrapper<MeiteUser> userQueryWrapper = new QueryWrapper<>();
Page<MeiteUser> pageResult = meiteUserMapper.selectPage(page, userQueryWrapper);
return pageResult.getRecords();
}
}
条件构造器
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为、
等于查询
分页插件
package com.taotao.mybatisplus1.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
*@author tom
*Date 2020/6/16 0016 22:44
*分页插件组合
*/
@EnableTransactionManagement
@Configuration
@MapperScan("com.taotao.mybatisplus1.mapper")
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor paginationInterceptor=new PaginationInterceptor();
//设置请求的页面大于最大页后操作,true调回到首页,false 继续请求
paginationInterceptor.setOverflow(false);
//设置最大页限制数量。默认为500条,-1 不限制
paginationInterceptor.setLimit(10);
//开启count d join 优化只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
/**
* 整合乐观锁插件 改写我们的sql语句 加上版本号码
* @return
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
自定义主键id
package com.taotao.mybatisplus1.config;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.stereotype.Component;
/**
*@author tom
*Date 2020/6/17 0017 8:25
*自定义分布式主键id
*/
@Component
public class CustomIdGenerator implements IdentifierGenerator {
@Override
public Long nextId(Object entity) {
return 60L;
}
}
实体类主键id改为自定义形式
@Data
@EqualsAndHashCode(callSuper = false)
public class MeiteUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "user_id", type = IdType.ASSIGN_ID)
private Integer userId;
雪花算法:
package com.taotao.mybatisplus1.utils;
import org.springframework.stereotype.Component;
@Component
public class SnowflakeIdUtils {
// ==============================Fields===========================================
/**
* 开始时间截 (2015-01-01)
*/
private final long twepoch = 1420041600000L;
/**
* 机器id所占的位数
*/
private final long workerIdBits = 5L;
/**
* 数据标识id所占的位数
*/
private final long datacenterIdBits = 5L;
/**
* 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
*/
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/**
* 支持的最大数据标识id,结果是31
*/
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/**
* 序列在id中占的位数
*/
private final long sequenceBits = 12L;
/**
* 机器ID向左移12位
*/
private final long workerIdShift = sequenceBits;
/**
* 数据标识id向左移17位(12+5)
*/
private final long datacenterIdShift = sequenceBits + workerIdBits;
/**
* 时间截向左移22位(5+5+12)
*/
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/**
* 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
*/
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 工作机器ID(0~31)
*/
private long workerId;
/**
* 数据中心ID(0~31)
*/
private long datacenterId;
/**
* 毫秒内序列(0~4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的时间截
*/
private long lastTimestamp = -1L;
//==============================Constructors=====================================
public SnowflakeIdUtils() {
this.workerId = 3;
this.datacenterId = 1;
}
/**
* 构造函数
*
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdUtils(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
//==============================Test=============================================
/**
* 测试
*/
public static void main(String[] args) {
SnowflakeIdUtils idWorker = new SnowflakeIdUtils(3, 1);
System.out.println(idWorker.nextId());
}
}
优化自增id 配置:
package com.taotao.mybatisplus1.config;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.taotao.mybatisplus1.utils.SnowflakeIdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*@author tom
*Date 2020/6/17 0017 8:25
*自定义分布式主键id
*/
@Component
public class CustomIdGenerator implements IdentifierGenerator {
@Autowired
private SnowflakeIdUtils snowflakeIdUtils;
@Override
public Long nextId(Object entity) {
return snowflakeIdUtils.nextId();
}
}
image.png