來源于螞蟻課堂
1.Mybatis-plus與mybatis區(qū)別
2.BaseMapper接口實現(xiàn)快速增刪改查
3.實現(xiàn)復(fù)雜的QueryWrapper條件構(gòu)造器
4.mybatis-plus實現(xiàn)邏輯刪除
5.mybatis-plus整合分頁插件
6.mybatis-plus代碼自動生成器
7.mybatis-plus動態(tài)切換數(shù)據(jù)源
8.mybatis-plus生成全局的主鍵id
9.mybatis-plus樂觀鎖的機制
mybatisPlus介紹
MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具泵喘,在 MyBatis 的基礎(chǔ)上只做增強不做改變墩瞳,為簡化開發(fā)、提高效率而生,和hibernate怎静、jpa注解方式非常相似。
mybatisPlus特性
無侵入:只做增強不做改變,引入它不會對現(xiàn)有工程產(chǎn)生影響,如絲般順滑
損耗屑尉埂:啟動即會自動注入基本 CURD,性能基本無損耗洋侨,直接面向?qū)ο蟛僮?br>
強大的 CRUD 操作:內(nèi)置通用 Mapper舍扰、通用 Service,僅僅通過少量配置即可實現(xiàn)單表大部分 CRUD 操作希坚,更有強大的條件構(gòu)造器边苹,滿足各類使用需求
支持 Lambda 形式調(diào)用:通過 Lambda 表達(dá)式,方便的編寫各類查詢條件吏够,無需再擔(dān)心字段寫錯
支持主鍵自動生成:支持多達(dá) 4 種主鍵策略(內(nèi)含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
支持 ActiveRecord 模式:支持 ActiveRecord 形式調(diào)用锅知,實體類只需繼承 Model 類即可進(jìn)行強大的 CRUD 操作
支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
內(nèi)置代碼生成器:采用代碼或者 Maven 插件可快速生成 Mapper 播急、 Model 、 Service 售睹、 Controller 層代碼桩警,支持模板引擎,更有超多自定義配置等您來使用
內(nèi)置分頁插件:基于 MyBatis 物理分頁昌妹,開發(fā)者無需關(guān)心具體操作捶枢,配置好插件之后,寫分頁等同于普通 List 查詢
分頁插件支持多種數(shù)據(jù)庫:支持 MySQL飞崖、MariaDB烂叔、Oracle、DB2固歪、H2蒜鸡、HSQL、SQLite牢裳、Postgre逢防、SQLServer 等多種數(shù)據(jù)庫
內(nèi)置性能分析插件:可輸出 Sql 語句以及其執(zhí)行時間,建議開發(fā)測試時啟用該功能蒲讯,能快速揪出慢查詢
內(nèi)置全局?jǐn)r截插件:提供全表 delete 忘朝、 update 操作智能分析阻斷,也可自定義攔截規(guī)則判帮,預(yù)防誤操作
支持?jǐn)?shù)據(jù)庫
mysql 局嘁、 mariadb 、 oracle 脊另、 db2 导狡、 h2 、 hsql 偎痛、 sqlite 旱捧、 postgresql 、 sqlserver
達(dá)夢數(shù)據(jù)庫 踩麦、 虛谷數(shù)據(jù)庫 枚赡、 人大金倉數(shù)據(jù)庫
SpringBoot整合mybatisPlus
初始化表結(jié)構(gòu)
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>
* 服務(wù)實現(xiàn)類
* </p>
*
* @author jobob
* @since 2020-06-09
*/
@RestController
public class MeiteUserServiceImpl {
@Autowired
public MeiteUserMapper meiteUserMapper;
/**
* 根據(jù)id查詢數(shù)據(jù)
* @param userId
* @return
*/
@GetMapping("/findByUser")
public MeiteUser findByUser(Integer userId) {
MeiteUser meiteUser = meiteUserMapper.selectById(userId);
return meiteUser;
}
/**
* 插入數(shù)據(jù)
* @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();
}
}
條件構(gòu)造器
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父類
用于生成 sql 的 where 條件, entity 屬性也用于生成 sql 的 where 條件
注意: entity 生成的 where 條件與 使用各個 api 生成的 where 條件沒有任何關(guān)聯(lián)行為、
等于查詢
分頁插件
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();
//設(shè)置請求的頁面大于最大頁后操作,true調(diào)回到首頁,false 繼續(xù)請求
paginationInterceptor.setOverflow(false);
//設(shè)置最大頁限制數(shù)量谓谦。默認(rèn)為500條,-1 不限制
paginationInterceptor.setLimit(10);
//開啟count d join 優(yōu)化只針對部分 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所占的位數(shù)
*/
private final long workerIdBits = 5L;
/**
* 數(shù)據(jù)標(biāo)識id所占的位數(shù)
*/
private final long datacenterIdBits = 5L;
/**
* 支持的最大機器id贫橙,結(jié)果是31 (這個移位算法可以很快的計算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
*/
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/**
* 支持的最大數(shù)據(jù)標(biāo)識id,結(jié)果是31
*/
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/**
* 序列在id中占的位數(shù)
*/
private final long sequenceBits = 12L;
/**
* 機器ID向左移12位
*/
private final long workerIdShift = sequenceBits;
/**
* 數(shù)據(jù)標(biāo)識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;
/**
* 數(shù)據(jù)中心ID(0~31)
*/
private long datacenterId;
/**
* 毫秒內(nèi)序列(0~4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的時間截
*/
private long lastTimestamp = -1L;
//==============================Constructors=====================================
public SnowflakeIdUtils() {
this.workerId = 3;
this.datacenterId = 1;
}
/**
* 構(gòu)造函數(shù)
*
* @param workerId 工作ID (0~31)
* @param datacenterId 數(shù)據(jù)中心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();
//如果當(dāng)前時間小于上一次ID生成的時間戳卢肃,說明系統(tǒng)時鐘回退過這個時候應(yīng)當(dāng)拋出異常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一時間生成的疲迂,則進(jìn)行毫秒內(nèi)序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒內(nèi)序列溢出
if (sequence == 0) {
//阻塞到下一個毫秒,獲得新的時間戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//時間戳改變,毫秒內(nèi)序列重置
else {
sequence = 0L;
}
//上次生成ID的時間截
lastTimestamp = timestamp;
//移位并通過或運算拼到一起組成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一個毫秒莫湘,直到獲得新的時間戳
*
* @param lastTimestamp 上次生成ID的時間截
* @return 當(dāng)前時間戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒為單位的當(dāng)前時間
*
* @return 當(dāng)前時間(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
//==============================Test=============================================
/**
* 測試
*/
public static void main(String[] args) {
SnowflakeIdUtils idWorker = new SnowflakeIdUtils(3, 1);
System.out.println(idWorker.nextId());
}
}
優(yōu)化自增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();
}
}