MyBatis-Plus 学习笔记

it2025-10-14  1

MyBatis Plus

本文档基于 MyBatis-Plus 官方文档编写,详情请参见 MyBatis-Plus 官网

目录

MyBatis Plus

MyBatis Plus 概述

特性

支持数据库

入门程序

数据库语句

使用 Spring 步骤

使用 Spring Boot 步骤

配置 Spring 日志

配置 Spring Boot 日志

MyBatis-Plus 常用注解

@TableName

@TableId

@TableField

@Version

@EnumValue

@TableLogic

@SqlParser

@KeySequence

常见 CRUD 操作及扩展

Spring Boot 基本操作

Spring 基本操作

扩展: Wrapper 的使用


MyBatis Plus 概述

MyBatis-Plus 是一个 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达梦数据库 、 虚谷数据库 、 人大金仓数据库

入门程序

基本步骤

1、创建项目

2、导入依赖

3、编写相应配置文件

4、使用

数据库语句

数据库语句

CREATE DATABASE mybatisplus; USE mybatisplus; 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) );

数据库 Data 脚本

DELETE FROM user; 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');

使用 Spring 步骤

使用 Spring 步骤

1、创建 Maven 项目

2、 引入相应的依赖

<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>1.2.12</log4j.version> <mysql.version>8.0.16</mysql.version> <mybatis.version>3.4.5</mybatis.version> </properties> <dependencies> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- log start --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- log end --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>compile</scope> </dependency> </dependencies>

3、编写配置文件 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 扫描的位置 --> <context:component-scan base-package="com.mybatis.study" /> <!-- 导入 JDBC 配置文件 --> <context:property-placeholder location="jdbc.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClass}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置 MyBatis-Plus 类 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 扫描 Mapper 所在的包 --> <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.mybatis.study.mapper" /> </bean> <!-- 配置事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>

4、编写 pojo 类和 mapper 接口

pojo 类

@Data @NoArgsConstructor @AllArgsConstructor @TableName("user") public class User { private Long id; private String name; private Integer age; private String email; }

mapper 接口

@Repository public interface UserMapper extends BaseMapper<User> {}

5、 测试运行

测试类

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class UserTest { @Autowired private UserMapper userMapper; @Test public void test01(){ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }

测试结果

  1587958492400.png

使用 Spring Boot 步骤

使用 Spring Boot 步骤

1、创建 Spring Boot 项目

2、添加依赖

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1</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>

3、编写配置文件 application.yml

# DataSource Config spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatisplus username: root password: 123

4、在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 mapper 文件夹

@MapperScan("com.mybatis.study.mapper") @SpringBootApplication public class MybatisPlusStudyApplication { public static void main(String[] args) { SpringApplication.run(MybatisPlusStudyApplication.class, args); } }

5、编写 pojo 类和 mapper 接口

pojo 类

@Data @NoArgsConstructor @AllArgsConstructor public class User implements Serializable { private Long id; private String name; private Integer age; private String email; }

mapper 接口

public interface UserMapper extends BaseMapper<User> {}

6、运行测试

测试类

@SpringBootTest class MybatisPlusStudyApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }

运行结果

   

配置 Spring 日志

导入 Log4J 日志的坐标

<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency>

编写 log4j 的配置文件

log4j.rootLogger=DEBUG,Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.console.Target=System.out log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.org.apache=ERROR log4j.logger.org.mybatis=ERROR log4j.logger.org.springframework=ERROR #这个需要 log4j.logger.log4jdbc.debug=ERROR log4j.logger.com.gk.mapper=ERROR log4j.logger.jdbc.audit=ERROR log4j.logger.jdbc.resultset=ERROR #这个打印SQL语句非常重要 log4j.logger.jdbc.sqlonly=DEBUG log4j.logger.jdbc.sqltiming=ERROR log4j.logger.jdbc.connection=FATAL

配置 Spring Boot 日志

在 Spring Boot 中配置日志(编写配置文件 application.yml)

# 配置日志 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

运行程序

   

MyBatis-Plus 常用注解

@TableName

描述:表名注解 属性类型必须指定默认值描述valueString否""表名schemaString否""schemakeepGlobalPrefixboolean否false是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)resultMapString否""xml 中 resultMap 的 idautoResultMapboolean否false是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)

@TableId

描述:主键注解 属性类型必须指定默认值描述valueString否""主键字段名typeEnum否IdType.NONE主键类型

IdType

值描述AUTO数据库ID自增NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)INPUTinsert前自行set主键值ASSIGN_ID分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)ASSIGN_UUID分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)ID_WORKER分布式全局唯一ID 长整型类型(please use ASSIGN_ID)UUID32位UUID字符串(please use ASSIGN_UUID)ID_WORKER_STR分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

@TableField

描述:字段注解(非主键) 属性类型必须指定默认值描述valueString否""字段名elString否""映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分existboolean否true是否为数据库表字段conditionString否""字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考updateString否""字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)insertStrategyEnumNDEFAULT举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)updateStrategyEnumNDEFAULT举例:IGNORED: update table_a set column=#{columnProperty}whereStrategyEnumNDEFAULT举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>fillEnum否FieldFill.DEFAULT字段自动填充策略selectboolean否true是否进行 select 查询keepGlobalFormatboolean否false是否保持使用全局的 format 进行处理jdbcTypeJdbcType否JdbcType.UNDEFINEDJDBC类型 (该默认值不代表会按照该值生效)typeHandlerClass<? extends TypeHandler>否UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)numericScaleString否""指定小数点后保留的位数

FieldStrategy

值描述IGNORED忽略判断NOT_NULL非NULL判断NOT_EMPTY非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)DEFAULT追随全局配置

FieldFill

值描述DEFAULT默认不处理INSERT插入时填充字段UPDATE更新时填充字段INSERT_UPDATE插入和更新时填充字段

@Version

描述:乐观锁注解、标记 @Verison 在字段上

@EnumValue

描述:通枚举类注解(注解在枚举字段上)

@TableLogic

描述:表字段逻辑处理注解(逻辑删除) 属性类型必须指定默认值描述valueString否""逻辑未删除值delvalString否""逻辑删除值

@SqlParser

描述:租户注解,支持method上以及mapper接口上 属性类型必须指定默认值描述filterboolean否falsetrue: 表示过滤SQL解析,即不会进入ISqlParser解析链,否则会进解析链并追加例如tenant_id等条件

@KeySequence

描述:序列主键策略 oracle属性:value、resultMap 属性类型必须指定默认值描述valueString否""序列名clazzClass否Long.classid的类型, 可以指定String.class,这样返回的Sequence值是字符串"1"

常见 CRUD 操作及扩展

Spring Boot 基本操作

前期准备步骤参见[使用 Spring Boot 步骤](#使用 Spring Boot 步骤)

插入操作

简单的插入操作

@Test void insertTest(){ User user = new User(); user.setName("Mybatis"); user.setAge(11); user.setEmail("123456@qq.com"); int insert = userMapper.insert(user); System.out.println(insert); }

运行结果

   

由于我们在插入操作时并没有指定 user 表的主键,但是查询数据库后发现 MyBatis-Plus 帮我们自动生成了主键。这是 MyBatis-Plus 的主键生成策略!

   

主键生成策略

默认 ID_WORKER 全局唯一 ID,在 MyBatis-Plus 3.3.0 版本后被 ASSIGN_ID 代替,详情见 MyBatis-Plus 常用注解-IdType

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

配置主键自增策略

在实体类的主键上加上 @TableId(type =IdType.AUTO)

将数据库中的主键字段设置为自增长

ALTER TABLE USER CHANGE id id BIGINT AUTO_INCREMENT     测试插入        

其余字段详情见 MyBatis-Plus 常用注解-IdType

更新操作

简单的更新操作

@Test void updateTest() { User user = User.builder() .id(5L) .name("Updated") .age(99) .build(); userMapper.updateById(user); }    

自动填充

阿里开发手册:所有的数据库表基本都需要配置上:gmt_create(create_time)、gmt_update(update_time) 并且实现自动化

在工作中不允许我们修改数据库,此处仅为演示

方式一:使用数据库级别完成

在数据表中新增字段 create_time ,update_time ALTER TABLE USER ADD create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'; ALTER TABLE USER ADD update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间';    

在实体类中新增属性

private Date createTime; private Date updateTime;

执行更新操作

@Test void updateTest() { User user = User.builder() .id(4L) .name("UpdatedTime") .age(55) .build(); userMapper.updateById(user); }

更新查看结果

更新前

   

更新后

   

方式二:使用代码完成

将数据表的默认值和更新操作删除

ALTER TABLE USER CHANGE create_time create_time DATETIME NULL COMMENT '创建时间', CHANGE update_time update_time DATETIME NULL COMMENT '修改时间';

在实体类上增加注解

@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;

编写处理器处理注解

@Slf4j @Component public class MyDateObjectHandler implements MetaObjectHandler { /** * 插入时的策略 * @param metaObject 源数据对象 */ @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill......"); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } /** * 更新时的策略 * @param metaObject 源数据对象 */ @Override public void updateFill(MetaObject metaObject) { log.info("start update fill......"); this.setFieldValByName("updateTime",new Date(),metaObject); } } 执行更新操作        

乐观锁

乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论做什么都不上锁!如果出现了问题,再次更新值测试。

悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论做什么都上锁!再去进行操作。

乐观锁实现方式:

取出记录时,获取当前的 version更新时,带上这个 version执行更新时, update xxx set version = newVersion where version = oldVersion如果 version 不正确,则更新失败 乐观锁:1、先查询,获得版本号 version = 1 -- A update user set name = "kuangshen", version = version + 1 where id = 2 and version = 1 -- B 线程抢先完成,这个时候version = 2,会导致A 修改失败! update user set name = "kuangshen", version = version + 1 where id = 2 and version = 1

乐观锁的使用

在数据库中新增 version 字段

ALTER TABLE USER ADD VERSION INT DEFAULT 1 COMMENT '版本号';

在实体类中增加 version 字段

@Version private Integer version;

注册组件

@MapperScan("com.hsh.study.mapper") @EnableTransactionManagement @Configuration public class MyBatisPlusConfig { /** * 注册乐观锁插件 * @return 实例 */ @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor(){ return new OptimisticLockerInterceptor(); } }

进行测试

测试方法

@Test void optimisticLockerTest() { User user = userMapper.selectById(1L); user.setName("lockedTest"); user.setEmail("110@test.com"); userMapper.updateById(user); }

测试结果

       

删除操作

删除操作常见的三种方式

/** * 根据 id 删除 */ @Test void deleteTest(){ userMapper.deleteById(1255372915881406466L); } /** * 通过 Id 集合进行删除 */ @Test void deleteIdsTest(){ userMapper.deleteBatchIds(Arrays.asList(1255373036727685122L,1255373036727685123L)); } /** * 通过 Map 来删除 */ @Test void deleteMapTest(){ Map<String, Object> map = new HashMap<>(); map.put("name","张三"); userMapper.deleteByMap(map); }

逻辑删除

逻辑删除:通过一个标记表示此条数据已被删除,不会再数据库中直接删除数据!deleted = 0 -> deleted = 1

物理删除:从数据库中直接删除

1、修改数据库,添加 deleted 字段

alter table `user` add deleted int default 0 comment '逻辑删除';

2、在实体类中添加 deleted 字段

在配置文件 application.yml 中加入配置

# 配置 MyBatis-Plus mybatis-plus: configuration: # 配置日志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置逻辑删除 global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0

在实体类上添加 @TableLogic 注解

@TableLogic private Integer deleted;

4、测试删除

   

查看数据库

   

查询操作

常见的查询操作

@Test void test1(){ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } @Test void test2(){ User user = userMapper.selectById(3L); System.out.println(user); } @Test void test3(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 1255379859656523778L)); // 查询不到 1255379859656523778L 是因为之前被逻辑删除了! users.forEach(System.out::println); } @Test void test4(){ HashMap<String, Object> map = new HashMap<>(); map.put("email","123456@qq.com"); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }

分页查询

MyBatis-Plus 中内置了分页插件

1、配置分页插件

/** * 分页插件 * @return 实例 */ @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); }

2、使用

@Test void pageLimitTest(){ /* new Page(current,size) * current:当前页 * size:每页大小 */ Page<User> page = new Page<>(1,5); // 执行分页查询 自动回写到 page 对象中 userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }

Spring 基本操作

前期准备步骤参见[使用 Spring 步骤](#使用 Spring 步骤)

插入操作

简单的插入操作

@Test public void insertTest(){ User user = User.builder() .name("hhh") .age(112) .email("123@11.11") .build(); userMapper.insert(user); }

运行结果

   

更新操作

简单的更新操作

@Test void updateTest() { User user = User.builder() .id(1257194050558160897L) .name("1122") .age(36) .build(); userMapper.updateById(user); }    

自动填充策略

阿里开发手册:所有的数据库表基本都需要配置上:gmt_create(create_time)、gmt_update(update_time) 并且实现自动化

方式一:使用数据库级别完成 参考 Spring Boot 中的自动填充,此处不做演示

方式二:使用代码完成

将数据表的默认值和更新操作删除

ALTER TABLE USER CHANGE create_time create_time DATETIME NULL COMMENT '创建时间', CHANGE update_time update_time DATETIME NULL COMMENT '修改时间';

在实体类上增加注解

@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;

编写处理器处理注解

@Slf4j @Component public class MyDateObjectHandler implements MetaObjectHandler { /** * 插入时的策略 * @param metaObject 源数据对象 */ @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill......"); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } /** * 更新时的策略 * @param metaObject 源数据对象 */ @Override public void updateFill(MetaObject metaObject) { log.info("start update fill......"); this.setFieldValByName("updateTime",new Date(),metaObject); } }

编写 applicationContext.xml 配置文件

<!-- 配置 MyBatis-Plus 的全局配置 --> <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"> <property name="metaObjectHandler"> <!-- 编写自己的 MyMetaObjectHandler --> <bean class="com.mybatis.study.handler.MyMetaObjectHandler" /> </property> </bean> <!-- 配置 MyBatis-Plus 类 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="globalConfig" ref="globalConfig" /> </bean> 执行更新操作        

乐观锁

乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论做什么都不上锁!如果出现了问题,再次更新值测试。

悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论做什么都上锁!再去进行操作。

乐观锁实现方式:

取出记录时,获取当前的 version更新时,带上这个 version执行更新时, update xxx set version = newVersion where version = oldVersion如果 version 不正确,则更新失败

乐观锁的使用

在数据库中新增 version 字段

ALTER TABLE USER ADD VERSION INT DEFAULT 1 COMMENT '版本号';

在实体类中增加 version 字段

@Version private Integer version;

注册组件,配置 applicationContext.xml 配置文件

<!-- 配置 MyBatis-Plus 类 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <!-- 配置数据源 --> <property name="dataSource" ref="dataSource" /> <!-- 配置全局配置 --> <property name="globalConfig" ref="globalConfig" /> <!-- 配置插件 --> <property name="plugins"> <list> <!-- 注册乐观锁插件 --> <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor" /> </list> </property> </bean>

进行测试

测试方法

@Test public void optimisticLockerTest() { User user = userMapper.selectById(1257194050558160897L); user.setName("lockedTest"); user.setEmail("120@test.com"); userMapper.updateById(user); }

测试结果

       

删除操作

删除操作常见的三种方式

/** * 根据 id 删除 */ @Test void deleteTest(){ userMapper.deleteById(1255372915881406466L); } /** * 通过 Id 集合进行删除 */ @Test void deleteIdsTest(){ userMapper.deleteBatchIds(Arrays.asList(1255373036727685122L,1255373036727685123L)); } /** * 通过 Map 来删除 */ @Test void deleteMapTest(){ Map<String, Object> map = new HashMap<>(); map.put("name","张三"); userMapper.deleteByMap(map); }

逻辑删除

逻辑删除:通过一个标记表示此条数据已被删除,不会再数据库中直接删除数据!deleted = 0 -> deleted = 1

物理删除:从数据库中直接删除

1、修改数据库,添加 deleted 字段

alter table `user` add deleted int default 0 comment '逻辑删除';

2、在实体类中添加 deleted 字段

在配置文件 applicationContext.xml 中加入配置

<!-- Mybatis-Plus 全局配置 --> <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"> <!-- 自动填充 --> <property name="metaObjectHandler"> <!-- 编写自己的 MyMetaObjectHandler --> <bean class="com.mybatis.study.handler.MyMetaObjectHandler" /> </property> <!-- 逻辑删除 --> <property name="dbConfig" > <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"> <property name="logicDeleteValue" value="1" /> <property name="logicNotDeleteValue" value="0" /> </bean> </property> </bean> <!-- 配置 MyBatis-Plus 类 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="globalConfig" ref="globalConfig" /> </bean>

在实体类上添加 @TableLogic 注解

@TableLogic private Integer deleted;

4、测试删除

   

查看数据库

   

查询操作

常见的查询操作

@Test void test1(){ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } @Test void test2(){ User user = userMapper.selectById(3L); System.out.println(user); } @Test void test3(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 1255379859656523778L)); // 查询不到 1255379859656523778L 是因为之前被逻辑删除了! users.forEach(System.out::println); } @Test void test4(){ HashMap<String, Object> map = new HashMap<>(); map.put("email","123456@qq.com"); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }

分页查询

MyBatis-Plus 中内置了分页插件

1、配置分页插件

<!-- 配置 MyBatis-Plus 类 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="globalConfig" ref="globalConfig" /> <property name="plugins"> <list> <!-- 配置分页插件 --> <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor" /> </list> </property> </bean>

2、使用

@Test void pageLimitTest(){ /* new Page(current,size) * current:当前页 * size:每页大小 */ Page<User> page = new Page<>(1,5); // 执行分页查询 自动回写到 page 对象中 userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }    

扩展: Wrapper 的使用

当我们需要写一些复杂 SQL 语句时,可以使用 Wrapper 代替,所用 Wrapper 参数解释参见 条件构造器

下面列举常用 Wrapper 及其使用结果

allEq

allEq -> 全部相等或个别 isNull

@Test void allEqTest(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); Map<String, Object> map = new HashMap<>(); map.put("name","张三"); map.put("age",null); wrapper.allEq(map); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }    

eq

eq -> 相等(用于判断一个条件时)

@Test void eqTest(){ wrapper.eq("email","123456@qq.com"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }    

inSql

有两种不同的用法:

​ 1. inSql("age","1,2,3,4,5") -> age IN (1,2,3,4,5)

​ 2. inSql("id","select id from user where id < 5") -> id IN (SELECT id FROM user WHERE id < 5)

@Test void inSqlTest1(){ wrapper.inSql("age","10,11,20"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } @Test void inSqlTest2(){ wrapper.inSql("id","select id from user where id < 10"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }        

其余常见方法参见如下映射表

方法名数据库名作用ne<>不等于gt>大于ge>=大于等于lt<小于le<=小于等于betweenBETWEEN 值1 AND 值2在值 1 和值 2 之间notBetweenNOT BETWEEN 值1 AND 值2不在值 1 和值 2 之间like / notLikeLIKE '%值%' / NOT LIKE '值'模糊搜索likeLeft / likeRightLIKE '%值' / LIKE '值%'左右模糊匹配isNull / isNotNullIS NULL / IS NOT NULL是否为空in / notInIN (值1,2...) / NOT IN (值1,2...)是否在集合中inSql / notInSql见例子子查询或查询集合groupByGROUP BY 字段根据字段分组orderByAsc / orderByDescORDER BY 字段 ASC / ORDER BY 字段 DESC升序排序 / 降序排序其余详细字段参见官方文档官方文档其余详细字段参见官方文档
最新回复(0)