MyBatisPlus快速入门

MyBatisPlus概述和快速入门

概述

基础框架

  • MyBatis
  • Spring
  • SpringMVC

为什么需要学习?

MyBatisPlus可以节省我们大量的工作时间,所有的CRUD都可以自动化完成。还有其他框架JPAtk-mapper

简介

是什么?

Mybatis本来就是简化JDBC操作的!MyBatis-Plus是一个Mybatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

愿景

成为 MyBatis 最好的搭档,就像 魂斗罗中的 1P2P,基友搭配,效率翻倍。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,BaseMapper
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,以后简单的CRUD操作,它不用自己编写了!
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 MapperModelServiceController 层代码,支持模板引擎,更有超多自定义配置等您来使用(自动帮助我们生成代码)
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQLMariaDBOracleDB2H2HSQLSQLitePostgreSQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 deleteupdate 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

使用第三方库,学习流程

  1. 导入对应的依赖
  2. 研究依赖如何配置
  3. 代码如何编写
  4. 提高扩展技术能力

步骤

  1. 创建数据库test
  2. 创建user
sql复制代码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)
);


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');


-- 真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified 这些字段也是需要的
  1. 编写项目,初始化项目,使用Spirngboot初始化项目。
  2. 导入依赖
xml复制代码<!--数据库驱动-->  
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->  
<dependency>  
 <groupId>mysql</groupId>  
 <artifactId>mysql-connector-java</artifactId>  
</dependency>  
  
<!--Mybatis-plus-->  
<!--Mybatis-plus 是自己开发的,并非官方的!-->  
<dependency>  
 <groupId>com.baomidou</groupId>  
 <artifactId>mybatis-plus-boot-starter</artifactId>  
 <version>3.4.3.4</version>  
</dependency>  
  
<!--lombok-->  
<dependency>  
 <groupId>org.projectlombok</groupId>  
 <artifactId>lombok</artifactId>  
</dependency>

说明:我们使用Mybatis-plus可以节省我们大量的代码,尽量不要同时导入MyBatisMybatis-plus,有版本的差异。 5. 连接数据库,这一步和Mybatis相同!

properties复制代码# 根据自己的数据库配置

# mysql 5  
spring.datasource.username=root  
spring.datasource.password=123456  
# useSSL 安全连接;useUnicode 是否使用Unicode字符集;characterEncoding 字符集;  
# mysql 8 驱动不同,需要增加时区 serverTimezone=GMT%2B8spring.datasource.url=jdbc:mysql://localhost/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8  
# 使用 8 的驱动,高版本兼容低版本  
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  1. 传统方式:pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller ; 使用mybatis-plus之后:
  • pojo
java复制代码@Data  
@NoArgsConstructor  
@AllArgsConstructor  
public class User {  
 private Long id;  
    private String name;  
    private Integer age;  
    private String email;  
}
  • mapper接口
java复制代码/**  
 * 在对应的 mapper 上面实现继承基本的类 BaseMapper  
 */
@Repository  
public interface UserMapper extends BaseMapper<User> {  
  
 /*  
 * 所有的CRUD操作都已经编写完成了  
 * 不需要配置一大推文件了  
 */
 }

注意点:需要在主启动类上去扫描我们的mapper包下的所有接口。@MapperScan("com.zbc.mybatis_plus_demo.mapper")

  • 测试类中测试
java复制代码@SpringBootTest  
class MybatisPlusDemoApplicationTests {  
  
 /**  
 * 继承了 BaseMapper,所有的方法都来自己的父类  
 * 我们也可以编写自己的扩展方法  
 */  
 @Autowired  
 private UserMapper userMapper;  
  
 @Test  
 void contextLoads() {  
  
 //参数是一个 wrapper,条件构造器  
 //查询所有用户  
 List<User> users = userMapper.selectList(null);  
        users.forEach(System.out::println);  
    }  
}

Pasted image 20211105233655.png

思考问题

  • SQL谁帮我们写的? Mybatis-Plus
  • 方法从哪里来的?Mybatis-Plus

配置日志

我们所有的sql现在是不可见的,我们需要知道是怎么执行的,还有在开发过程中调试以及查找定位问题的时候需要查看。在开发和测试环境可以配置,生产环境不需要配置(因为产生大量不必要的日志,并且对性能有一点影响)。 在application.properties中假如以下配置

properties复制代码# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

重新执行刚才的测试代码

log复制代码Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d717f19] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1180105925 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c16677c] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user 
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5d717f19]
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

Insert插入

java复制代码//测试插入  
@Test  
public void testInsert() {  
    User user = new User();  
    user.setName("zbc");  
    user.setAge(20);  
    user.setEmail("test@163.com");  
  
    //帮我们自动生成id  
    int result = userMapper.insert(user);  
    //受影响的行数  
    System.out.println(result);  
    //发现,id会自动回填  
    System.out.println(user);  
}
log复制代码Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@18715bb] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1180105925 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c16677c] will not be managed by Spring
==>  Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) 
==> Parameters: 1456795944390905857(Long), zbc(String), 20(Integer), test@163.com(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@18715bb]
1
User(id=1456795944390905857, name=zbc, age=20, email=test@163.com)

数据库插入的id是全局唯一id1456795944390905857是基于雪花算法生成。

主键生成策略

MybatisPlus中关于主键生成策略有一个专门的注解(@TableId)

java复制代码@Documented  
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.FIELD})  
public @interface TableId {  
    String value() default "";  
  
    IdType type() default IdType.NONE;  
}

IdType是策略的类型

java复制代码public enum IdType {  
    AUTO(0),  
    NONE(1),  
    INPUT(2),  
    ASSIGN_ID(3),  
    ASSIGN_UUID(4);  
  
    private final int key;    
}
  • AUTO
    

    :数据库

    ID
    

    自增

    • 需要在实体类字段上添加@TableId(type = IdType.AUTO)
    • 数据库字段也必须是自增。
    • 再次测试,我们发现id自增1
  • NONE: 默认方案,未设置主键

  • INPUT:插入前手动设置主键,一旦设置之后就需要配置id

  • ASSIGN_ID:分配ID(主键类型为Number(LongInteger)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

  • ASSIGN_UUID:分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)

  • ID_WORKER:分布式全局唯一ID,主键类型Long,后续建议使用ASSIGN_ID

  • UUID32UUID字符串,主键类型String,后续建议使用ASSIGN_UUID

  • ID_WORKER_STR:分布式全局唯一ID,主键类型String,后续建议使用ASSIGN_ID

雪花算法:snowflakeTwitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一。

UUID:国际标准化组织ISO提出的一个概念,是一个128bit的数字,也可以表现为3216进制的字符,中间用-分割。

  • 时间戳+UUID版本号,分三段占16个字符(60bit+4bit),
  • Clock Sequence号与保留字段,占4个字符(13bit3bit),
  • 节点标识占12个字符(48bit),
  • 示例:3F2504E0-4F89-11D3-9A0C-0305E82C3301

update更新

java复制代码//测试更新  
@Test  
public void testUpdate() {  
    User user = new User();  
    //通过条件自动拼接动态sql  
    user.setId(1L);  
    user.setName("zbc");  
    user.setAge(14);  
    //注意:updateById 实际传参是一个 对象,并不是id  
    int result = userMapper.updateById(user);  
    System.out.println(result);  
    System.out.println(user);  
}

所有的sql都是自动帮你配置的

自动填充

创建时间、修改时间,这些字段都是自动化完成的,我们不希望手动更新。(阿里巴巴开发手册:所有的数据库表:gmt_creategmt_modified这两个字段几乎所有的表都需要配置上,而且需要自动化)

数据库级别(不建议使用)

  • 在表中新增字段create_timeupdate_time
sql复制代码-- 添加 create_time 设置默认时间 CURRENT_TIMESTAMP
ALTER TABLE `table_name`  
ADD COLUMN `create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';

-- 修改 create_time 设置默认时间 CURRENT_TIMESTAMP
ALTER TABLE `table_name`  
MODIFY COLUMN `create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';

-- 添加 update_time 设置默认时间 CURRENT_TIMESTAMP 设置更新时间为 ON UPDATE CURRENT_TIMESTAMP
ALTER TABLE `table_name`  
ADD COLUMN `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间';

-- 修改 update_time 设置默认时间 CURRENT_TIMESTAMP 设置更新时间为 ON UPDATE CURRENT_TIMESTAMP
ALTER TABLE `table_name`  
MODIFY COLUMN `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间';
  • 测试插入方法,需要同步实体类字段
java复制代码private Date createTime;  
private Date updateTime;
idnameageemailcreate_timeupdate_time
1456795944390905861zbc20test@163.com2021-11-07 17:29:332021-11-07 17:29:33
  • 测试更新方法
idnameageemailcreate_timeupdate_time
1456795944390905861zbc14test@163.com2021-11-07 17:29:332021-11-07 17:34:39

代码级别

  • 删除数据库级别
sql复制代码-- 去掉 create_time 默认值
ALTER TABLE `table_name`  
MODIFY COLUMN `create_time` TIMESTAMP NULL COMMENT '创建时间';

-- 去掉 update_time 默认值和默认更新
ALTER TABLE `table_name`  
MODIFY COLUMN `update_time` TIMESTAMP NULL COMMENT '修改时间';
  • 实体类字段数据增加注解
java复制代码@TableField(fill = FieldFill.INSERT)  
private Date createTime;  
@TableField(fill = FieldFill.INSERT_UPDATE)  
private Date updateTime;
java复制代码//填充类型说明:
public enum FieldFill {  
	 /**  
	 * 默认不处理  
	 */  
	 DEFAULT,  
	/**  
	 * 插入时填充字段  
	 */  
	 INSERT,  
	/**  
	 * 更新时填充字段  
	 */  
	 UPDATE,  
	/**  
	 * 插入和更新时填充字段  
	 */  
	 INSERT_UPDATE  
}
  • 编写处理器来处理这个注解
java复制代码package com.zbc.mybatis_plus_demo.handler;  
  
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;  
import lombok.extern.slf4j.Slf4j;  
import org.apache.ibatis.reflection.MetaObject;  
import org.springframework.stereotype.Component;  
  
import java.util.Date;  
  
/**  
 * 不要忘记把处理器加到IOC容器中  
 *  
 * @author zbc * @date 2021/11/7 
 */  
@Slf4j  
@Component  
public class MyMetaObjectHandler implements MetaObjectHandler {  
  
 /**  
 * 插入时的填充策略  
 *  
 * @param metaObject 元数据  
 */  
 @Override  
 public void insertFill(MetaObject metaObject) {  
 	//setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)  
 	this.setFieldValByName("createTime", new Date(), metaObject);  
	this.setFieldValByName("updateTime", new Date(), metaObject);  
 }  
  
 /**  
 * 更新时的填充策略  
 *  
 * @param metaObject 元数据  
 */  
 @Override  
 public void updateFill(MetaObject metaObject) {  
 	this.setFieldValByName("updateTime", new Date(), metaObject);  
 }  
}

乐观锁

  • 悲观锁:认为数据是不安全的,随时可能都有变动,无论什么时候都会加锁。再操作。
  • 乐观锁:相对悲观锁而言,乐观锁任务数据是安全的,一般情况下不会出现问题,无论干什么都不去上锁。如果出现冲突,则返回错误信息,交给用户决定。

乐观锁实现方式

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

使用乐观锁

  • 数据库增加version字段:
sql复制代码ALTER TABLE `table_name`  
ADD COLUMN `version` INT DEFAULT 1 COMMENT '乐观锁';
  • 给实体类增加字段
java复制代码@Version  
private Integer version;
  • 注册乐观锁组件
java复制代码@Configuration  
@EnableTransactionManagement  
public class MyBatisPlusConfig {  
  
 /**  
 * 用来配置mybatisPlus 插件 
 *  
 * @return 拦截器  
 */  
 @Bean  
 public MybatisPlusInterceptor mybatisPlusInterceptor() {  
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();  
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());  
        return interceptor;  
    }  
}
  • 测试成功
java复制代码//测试乐观锁成功  
@Test  
public void testOptimisticLocker() {  
	 //1.先获取用户信息  
	 User user = userMapper.selectById(1L);  
	 //2.修改用户信息  
	 user.setName("test");  
	 user.setAge(25);  
	 //3.执行更新操作  
	 userMapper.updateById(user);  
}
log复制代码Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74431b9c] was not registered for synchronization because synchronization is not active
2021-11-07 18:41:52.417  INFO 21884 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-11-07 18:41:52.792  INFO 21884 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1729992636 wrapping com.mysql.cj.jdbc.ConnectionImpl@774f2992] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=?
==> Parameters: 1(Long)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, zbc, 14, test1@baomidou.com, null, 2021-11-06 22:28:53, 1
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74431b9c]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74ce7fdf] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@33779587 wrapping com.mysql.cj.jdbc.ConnectionImpl@774f2992] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: test(String), 25(Integer), test1@baomidou.com(String), 2021-11-07 18:41:52.93(Timestamp), 2(Integer), 1(Long), 1(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74ce7fdf]
  • 测试失败
java复制代码//测试乐观锁失败  
@Test  
public void testOptimisticLocker2() {  
  
	 //线程1  
	 User user = userMapper.selectById(1L);  
	 user.setName("test1");  

	 //模拟线程2,先一步执行修改操作  
	 User user2 = userMapper.selectById(1L);  
	 user2.setName("test2");  
	 userMapper.updateById(user2);  

	 //如果没有乐观锁,就会覆盖线程2的值   
	 userMapper.updateById(user);  
}
log复制代码Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f2fb225] was not registered for synchronization because synchronization is not active
2021-11-07 18:46:35.982  INFO 13340 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-11-07 18:46:36.457  INFO 13340 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@2001676690 wrapping com.mysql.cj.jdbc.ConnectionImpl@602298b] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=?
==> Parameters: 1(Long)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, test, 25, test1@baomidou.com, null, 2021-11-07 18:41:53, 2
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f2fb225]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@13908f9c] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@849031967 wrapping com.mysql.cj.jdbc.ConnectionImpl@602298b] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=?
==> Parameters: 1(Long)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, test, 25, test1@baomidou.com, null, 2021-11-07 18:41:53, 2
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@13908f9c]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@642c72cf] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@966457052 wrapping com.mysql.cj.jdbc.ConnectionImpl@602298b] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: test2(String), 25(Integer), test1@baomidou.com(String), 2021-11-07 18:46:36.63(Timestamp), 3(Integer), 1(Long), 2(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@642c72cf]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6aa6c17] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1196877260 wrapping com.mysql.cj.jdbc.ConnectionImpl@602298b] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: test1(String), 25(Integer), test1@baomidou.com(String), 2021-11-07 18:46:36.68(Timestamp), 3(Integer), 1(Long), 2(Integer)
<==    Updates: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6aa6c17]

Select查询

java复制代码//测试查询
@Test
public void testSelect() {
    //根据id查询
    User user = userMapper.selectById(1L);
    System.out.println(user);

    //批量查询
    List<User> users = userMapper.selectBatchIds(Arrays.asList(2L, 3L));
    users.forEach(System.out::println);

    //条件查询 map
    Map<String, Object> map = new HashMap<>();
    map.put("name", "zbc");
    List<User> users1 = userMapper.selectByMap(map);
    users1.forEach(System.out::println);
}
log复制代码//根据id查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=?
==> Parameters: 1(Long)

//批量查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id IN ( ? , ? )
==> Parameters: 2(Long), 3(Long)

//条件查询 map
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE name = ?
==> Parameters: zbc(String)

分页查询

实现方式

  • 原始分页limit
  • 第三方插件pageHelper
  • MyBatisPlus自带分页功能

使用分页查询

  • 增加分页插件,分页插件需要在乐观锁插件前面添加
java复制代码@Configuration
@EnableTransactionManagement
public class MyBatisPlusConfig {

    /**
     * 用来配置mybatisPlus 插件
     *
     * @return 拦截器
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件,注意数据库的类型
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
  • 直接使用Page对象即可
java复制代码//测试分页查询  
@Test  
public void testPage() {  
    //参数1:页码,参数2:每页记录数  
    Page<User> page = new Page<>(1, 5);  
    userMapper.selectPage(page, null);  
    page.getRecords().forEach(System.out::println);  
}
log复制代码//先求总记录数
==>  Preparing: SELECT COUNT(*) AS total FROM user
==> Parameters: 
<==    Columns: total
<==        Row: 12
<==      Total: 1
//然后分页查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user LIMIT ?
==> Parameters: 5(Long)
//输出结果
User(id=1, name=test2, age=25, email=test1@baomidou.com, createTime=null, updateTime=Sun Nov 07 18:46:37 CST 2021, version=3)
User(id=2, name=Jack, age=20, email=test2@baomidou.com, createTime=null, updateTime=Sat Nov 06 22:28:53 CST 2021, version=1)
User(id=3, name=Tom, age=28, email=test3@baomidou.com, createTime=null, updateTime=Sat Nov 06 22:28:53 CST 2021, version=1)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com, createTime=null, updateTime=Sat Nov 06 22:28:53 CST 2021, version=1)
User(id=5, name=Billie, age=24, email=test5@baomidou.com, createTime=null, updateTime=Sat Nov 06 22:28:53 CST 2021, version=1)
12

delete删除

java复制代码//测试删除
@Test
public void testDelete() {
    //单个id删除
    userMapper.deleteById(1456795944390905863L);

    //批量id删除
    userMapper.deleteBatchIds(Arrays.asList(1456795944390905861L, 1456795944390905862L));

    //条件删除 map
    Map<String, Object> map = new HashMap<>();
    map.put("name", "123");
    userMapper.deleteByMap(map);
}
log复制代码//单个id删除
==>  Preparing: DELETE FROM user WHERE id=?
==> Parameters: 1456795944390905863(Long)
<==    Updates: 1
//批量id删除
==>  Preparing: DELETE FROM user WHERE id IN ( ? , ? )
==> Parameters: 1456795944390905861(Long), 1456795944390905862(Long)
<==    Updates: 2
//条件删除 map、
==>  Preparing: DELETE FROM user WHERE name = ?
==> Parameters: 123(String)
<==    Updates: 1

逻辑删除

  • 物理删除:从数据库中直接删除
  • 逻辑删除:从数据库中没有删除,而是通过一个变量来让它失效

应用场景:管理员可以查看被删除的记录,防止数据丢失,类似回收站。

使用

  • 增加deleted字段
sql复制代码ALTER TABLE `table_name`  
ADD COLUMN `deleted` INT(1) DEFAULT 1 COMMENT '逻辑删除';
  • 实体类增加属性
java复制代码@TableLogic  
private Integer deleted;
  • 增加逻辑删除配置
properties复制代码# 逻辑删除
# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置@TableLogic)
mybatis-plus.global-config.db-config.logic-delete-field=flag
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
  • 测试
java复制代码//测试逻辑删除
@Test
public void testLogicDelete(){
    userMapper.deleteById(1456795944390905864L);
    User user = userMapper.selectById(1456795944390905864L);
    System.out.println(user);
}
log复制代码==>  Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 1456795944390905864(Long)
<==    Updates: 1


==>  Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE id=? AND deleted=0
==> Parameters: 1456795944390905864(Long)
<==      Total: 0

null

本质上是更新操作并不是删除,而是修改操作。 查询的时候我们发现已经不能查找到了

条件构造器(重点)

条件构造器主要用来写一些复杂的sql

注意事项

不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输

  1. wrapper 很重
  2. 传输 wrapper 可以类比为你的 controllermap 接收值(开发一时爽,维护火葬场)
  3. 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作

拼接方法

查询方法说明示例
eq等于 =eq("username", "admin") —> username = 'admin'
ne等于 =ne("username", "admin") —> username <> 'admin'
gt大于 >gt("age", "18") —> age > 18
ge大于等于 >=ge("age", "18") —> age >= 18
lt小于 <lt("age", 18) —> age < 18
le小于等于 <=le("age", 18) —> age <= 18
between在值1和值2之间between("age", 18, 24) —> age BETWEEN 18 AND 24
notBetween不在值1和值2之间notBetween("age", 18, 24) —> age NOT BETWEEN 18 AND 24
like模糊查询like("name", "张") —> name LIKE '%张%'
notLike不模糊查询内notLike("name", "张") —> name NOT LIKE '%张%'
likeLeft左模糊查询likeLeft("name", "三") —> name LIKE '%三'
likeRight右模糊查询内likeRight("name", "张") —> name LIKE '张%'
isNull字段为空isNull("name") —> name IS NULL
isNotNull字段不为空isNotNull("name") —> name IS NOT NULL
in在集合内in("age", 16,17,18) —> age IN (16,17,18)
notIn在集合内notIn("age", 16,17,18) —> age NOT IN (16,17,18)
inSql子查询in("id", "SELECT id FROM table WHERE id < 3") —> id IN (SELECT id FROM table WHERE id < 3)
notInSql子查询notInSql("id", "SELECT id FROM table WHERE id < 3") —> id ONT IN (SELECT id FROM table WHERE id < 3)
groupBy分组groupBy("age", "id") —> GROUP BY id, name
orderByAsc字段正序orderByAsc("age") —> ORDER BY age ASC
orderByDesc字段倒序orderByDesc("age") —> ORDER BY age DESC
having分组筛选having("sum(age) > 10")—>HAVING SUM(age) > 10
oreq("id", 1).or().eq("name", "张三")—>id = 1 OR name = '张三'
andeq("id", 1).and().eq("name", "张三")—>id = 1 AND name = '张三'
exists存在exists("SELECT id FROM table WHERE age = 1")—>EXISTS (SELECT id FROM table WHERE age = 1)
notExists存在notExists("SELECT id FROM table WHERE age = 1")—>NOT EXISTS (SELECT id FROM table WHERE age = 1)

isNotnullge演示

java复制代码@Test  
void test1() {  
 //查询name不为空并且邮箱不为空,年龄大于15  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.  
            isNotNull("name").  
            isNotNull("email").  
            ge("age", 15);  
    userMapper.selectList(wrapper).forEach(System.out::println);  
}

eqselectOne演示

java复制代码@Test  
void test2() {  
 //查询name=test2  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.eq("name", "test2");  
    //selectOne 只能查询一个,假如出现多个结果会报错  
 User user = userMapper.selectOne(wrapper);  
    System.out.println(user);  
}

betweenselectCount演示

java复制代码@Test  
void test3() {  
 //查询年龄在[20,30]之间的用户  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.between("age", 20, 30);  
    long count = userMapper.selectCount(wrapper);  
    System.out.println(count);  
}

notLikelikeRightselectMaps演示

java复制代码@Test  
void test4() {  
 //name不包含bc,并且email以t开头(t%)  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.  
            notLike("name", "bc").  
            likeRight("email", "t");  
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);  
    maps.forEach(System.out::println);  
}

inSqlselectObjs和子查询演示

java复制代码@Test  
void test5() {  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.inSql("id", "SELECT id FROM user WHERE id < 10");  
    List<Object> objects = userMapper.selectObjs(wrapper);  
    objects.forEach(System.out::println);  
}

orderByDesc演示

java复制代码@Test  
void test6() {  
 QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.orderByDesc("id");  
    List<User> users = userMapper.selectList(wrapper);  
    users.forEach(System.out::println);  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值