一天入门MyBatisPlus
程序员文章站
2022-04-15 19:12:16
1、简介官网地址:https://mp.baomidou.com/MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。特性无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器...
1、简介
官网地址:https://mp.baomidou.com/
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 、 presto
- 达梦数据库 、 虚谷数据库 、 人大金仓数据库
2、快速搭建MyBatis-Plus
2.1 首先去创建一个数据库
drop table if exists user;
create table user(
id int primary key auto_increment, -- 主键id
name VARCHAR(255) not null, -- 姓名
age int not null, -- 年龄
email VARCHAR(50) -- 邮箱
);
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');
select * from user;
2.2创建springboot项目
2.2、1 添加依赖
向 pom.xml 中 添加依赖
<dependencies>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
2.2、2 配置application.yml
spring:
datasource:
username: root
password: ******
url: jdbc:mysql://localhost:3306/mbp?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
type: com.alibaba.druid.pool.DruidDataSource
#配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.2、3 编写实体类
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
2.2、4 编写mapper层
@Mapper
@Component
public interface UserMapper extends BaseMapper<User> {
}
2.2、4 开始测试
@SpringBootTest
class DemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}
3、CRUD
3.1 添加
@Test
public void add() {
User user = new User();
user.setAge(20);
user.setEmail("11111@qq.com");
user.setName("扬州炒饭");
userMapper.insert(user);
System.out.println(user);
}
这块id mybatis-plus会自动生成
注意:使用mysql数据库会添加失败
由于mybatis-plus会自动插入一个id到实体对象, 不管你是否对id设置值都会向实体类中添加一个long类型的值, 所以有时候导致一些意外的情况发生
所以这块建议在 实体类上加上主键策略
//对应数据库主键id IdType.AUTO主键自增 数据库中也必须设置自增
@TableId(type = IdType.ID_WORKER)
3.1 .1主键生成策略
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型(将跟随全局)
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
3.2 更新
@Test
public void update() {
User user = new User();
//通过条件自动拼接动态sql
user.setId(6);
user.setAge(20);
user.setEmail("11111@qq.com");
user.setName("扬州炒饭好吃吗");
userMapper.updateById(user);
System.out.println(user);
}
3.3 查询
批量查询:
//查询
@Test
public void select(){
//批量查询
List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
userList.forEach(System.out::print);
}
条件查询 map:
//按条件查询 map
@Test
public void selectBy(){
HashMap<String, Object> map = new HashMap<>();
map.put("version",1);
map.put("age",18);
List<User> userList = userMapper.selectByMap(map);
userList.forEach(System.out::print);
}
3.4 分页查询
-
配置拦截器
@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; }
3.5 自动填充
创建时间,修改时间
gmt_create,gmt_modified
1.给数据库添加字段
gmt_create datetime, -- 创建时间
gmt_modified datetime -- 修改时间
2.给实体类添加字段 并添加注解
@TableField(fill = FieldFill.INSERT)
private String gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String gmtModified;
3.添加处理器去 处理注解
@Slf4j
@Component
public class MyBatisPlusFill implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.setFieldValByName("gmtCreate", DateUtil.getTime(), metaObject);
this.setFieldValByName("gmtModified", DateUtil.getTime(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("gmtModified", DateUtil.getTime(), metaObject);
}
}
再去做测试就ok了
这里遇到的坑,官网最新的方法时间添加不上去,最后用了旧的方法
3.6 删除
//删除
@Test
public void delete(){
userMapper.deleteById(6);
}
//批量删除
@Test
public void deleteBatchIds(){
userMapper.deleteBatchIds(Arrays.asList(1,2,3,4,5,6));
}
//map删除
@Test
public void deleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("email","11111@qq.com");
userMapper.deleteByMap(map);
}
3.7 逻辑删除
在数据库中没有删除,通过字段使它查不到 好比回收站
3.7.1添加sql字段
deleted int DEFAULT '0' -- 逻辑删除
3.7.2 实体类加注解
@TableLogic //逻辑删除
private int deleted;
3.7.3 yml添加配置
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
删除其实执行的是
UPDATE user SET deleted=1 WHERE id=? AND deleted=0
查询的时候为添加上 where deleted=0 所以就查不出来了
4、乐观锁
- 乐观锁:不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
- 悲观锁:这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
测试
3.1首先给数据库添加字段
version int DEFAULT '1' -- 乐观锁
3.2 添加实体类
@Version //乐观锁
private int version;
3.3 注册组件
@MapperScan("com.chen.mapper")
@Configuration
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3.4测试
//测试乐观锁
@Test
public void testOptimisticLocker(){
User user = userMapper.selectById(1);
user.setName("炒饭");
user.setEmail("1111@Qq.com");
userMapper.updateById(user);
}
//测试乐观锁 多线程
@Test
public void test1OptimisticLocker(){
//线程1
User user = userMapper.selectById(1);
user.setName("炒饭");
user.setEmail("1111@Qq.com");
// 线程2 线程插队
User user1 = userMapper.selectById(1);
user1.setName("小炒饭");
user1.setEmail("2221@Qq.com");
userMapper.updateById(user1);
userMapper.updateById(user);
//如果没有乐观锁,线程1 就会覆盖线程2 的值
}
5、执行 SQL 分析打印
这块的话 我是用的druid 所以就不写了
需要的话直接官网看吧
6、条件构造器
package com.chen;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chen.mapper.UserMapper;
import com.chen.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* @author blackcats
* @date 2020/7/26 19:53
* 代码太难了
*/
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void test1(){
//查询name不为空 并且age >= 20
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.ge("age",20);
userMapper.selectList(wrapper);
}
@Test
public void test2(){
//查询name是 Tom 的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","Tom");
userMapper.selectOne(wrapper);//一条数据 使用 selectOne
}
@Test
public void test3(){
//查询年龄在 21 到 28的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",21,28); //包含21和28
userMapper.selectCount(wrapper);//查询结果数
}
//模糊查询
@Test
public void test4(){
//查询名字中带 a 的数据 并且邮箱以a开头
//左和右
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","a").likeRight("email","a");
//查询名字中不带 e 的数据
//QueryWrapper<User> wrapper = new QueryWrapper<>();
//wrapper.notLike("name","e");
userMapper.selectList(wrapper);//查询结果数
}
@Test
public void test5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//age在子查询中查出
wrapper.inSql("age","select age from user where age>18");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::print);
}
@Test
public void test6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//通过id降序排序
wrapper.orderByDesc("id");
List<User> userList = userMapper.selectList(wrapper);
userList.forEach(System.out::print);
}
@Test
public void test7(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询名字中有a 并且年龄大于20 的
wrapper.and(i -> i.like("name", "a").gt("age", "20"));
List<User> userList = userMapper.selectList(wrapper);
userList.forEach(System.out::print);
}
}
7、代码生成器
package com.chen;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
/**
* @author blackcats
* @date 2020/7/26 20:37
* 代码太难了
*/
public class CommunityCode {
public static void main(String[] args) {
//new出代码生成器对象
AutoGenerator mbp = new AutoGenerator();
// 全局配置 导入generator下的包
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("扬州炒饭"); //作者名字注释
gc.setOpen(false); //不打开资源管理器
gc.setFileOverride(false);// 是否覆盖
gc.setServiceName("%sService");//去掉service i 前缀
gc.setIdType(IdType.AUTO); //生成主键策略
mbp.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/community?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.NonRegisteringDriver");
dsc.setUsername("root");
dsc.setPassword("123456");
mbp.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog");
pc.setParent("chen");
pc.setController("controller");
pc.setEntity("pojo");
pc.setService("service");
pc.setMapper("mapper");
mbp.setPackageInfo(pc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user","question","comments","type"); //重点 一般主要就改这些地方 设置映射表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);// 自动lombok
//自动填充
TableFill gmt_create = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmt_modified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> list = new ArrayList<>();
list.add(gmt_create);
list.add(gmt_modified);
strategy.setTableFillList(list);
strategy.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段
//乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mbp.setStrategy(strategy);
mbp.execute();
}
}
总结
这个东西用着是很香,可是我不建议经常使用它
项目已经上传码云,点击跳转
本文地址:https://blog.csdn.net/qq_35800844/article/details/107599780
上一篇: java笔记_多态的相关使用