快速入门

准备工作

  1. 准备数据
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_name` varchar(20) NOT NULL COMMENT '用户名',
  `password` varchar(20) NOT NULL COMMENT '密码',
  `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `address` varchar(100) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

insert  into `user`(`id`,`user_name`,`password`,`name`,`age`,`address`) values (1,'ruiwen','123','瑞文',12,'山东'),(2,'gailun','1332','盖伦',13,'平顶山'),(3,'timu','123','提姆',22,'蘑菇石'),(4,'daji','1222','妲己',221,'狐山');
  1. 创建springboot项目
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  1. 创建启动类
@SpringBootApplication
public class SGApplication {

    public static void main(String[] args) {
        SpringApplication.run(SGApplication.class);
    }
}

准备实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String address;
}
  1. 添加mp依赖
 <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
 </dependency>
 <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  1. 配置数据库信息
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_db?characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  1. 创建mapper接口
public interface UserMapper extends BaseMapper<User> {}
  1. 配置mapper扫描
@SpringBootApplication
@MapperScan("com.sangeng.mapper") //在启动类上添加包
public class SGApplication {
    public static void main(String[] args) {
        SpringApplication.run(SGApplication.class,args);
    }
}


//或者,在每个mapper上添加@Mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {}
  1. 测试
@SpringBootTest
public class MPTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testQueryList(){
        System.out.println(userMapper.selectList(null));
    }
}
  1. 结果打印
[User(id=1, userName=ruiwen, password=123, name=瑞文, age=12, address=山东), User(id=2, userName=gailun, password=1332, name=盖伦, age=13, address=平顶山), User(id=3, userName=timu, password=123, name=提姆, age=22, address=蘑菇石), User(id=4, userName=daji, password=1222, name=妲己, age=221, address=狐山), User(id=1564511451302768641, userName=三更草堂222, password=7777, name=null, age=null, address=null)]

常用设置

映射规则

@TableName("tb_user") //表映射规则
public class User {
	@TableId(type = IdType.AUTO) //主键生成策略
    private Long id;
    @TableField("address")  //字段映射规则
    private String addressStr;
    
}

表映射规则

1.MP默认表名和实体类莫名一致
2.单独设置@TableName(“数据库表名”)
3.全局设置表名前缀,所有表名都比实体类多”tb_”前缀

mybatis-plus:
  global-config:
    db-config:
      #表名前缀
      table-prefix: tb_

主键生成策略

1.MP插入数据,没有设置主键生成策略时,默认基于雪花算法的自增id
2.使用其他策略定义实体类时,需要加@TableId注解,用type属性指定主键生成策略,单独设置
3.IdType取值

  • AUTO:数据库ID自增,依赖于数据库。(确保数据库设置ID自增)
  • NONE:未设置主键类型,若在代码中没有手动设置主键,根据主键的全局策略自动生成(默认主键全局策略是基于雪花算法自增ID)
  • INPUT:需要手动设置主键,若不设置,插入操作生成SQL时,会是null
  • ASSIGN_ID:当没有手动设置主键,即实体类中的主键属性为空时,才会自动填充,使用雪花算法
  • ASSIGN_UUID:当实体类的主键属性为空时,才会自动填充,使用UUID
    4.全局设置:
mybatis-plus:
  global-config:
    db-config:
      # id生成策略 auto为数据库自增
      id-type: auto

字段映射关系

1.默认实体类的属性名映射表的列名
2.属性名和列名不一致时,用@TabelField设置映射关系

字段和列名的驼峰映射

1.默认开启字段名到列名的驼峰命名(即从数据库a_id到属性aId的映射)
2.使用配置关闭

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false

日志

配置日志输出打印MP操作对应的SQL语句

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

在这里插入图片描述

基本使用

insert插入数据

  @Test
    public void testInsert(){
        User user = new User();
        user.setUserName("三更草堂333");
        user.setPassword("7777888");
        int r = userMapper.insert(user);
        System.out.println(r);
    }

deleteXXX删除数据

deleteBatchIds:批量删除
deleteById:根据id删除
deleteByMap:

 @Test
    public void testDelete(){
        List<Integer> ids = new ArrayList<>();
        ids.add(2);
        ids.add(3);
        ids.add(4);
        int i = userMapper.deleteBatchIds(ids);
        System.out.println(i);
    }

在这里插入图片描述

    @Test
    public void testDeleteById(){
        int i = userMapper.deleteById(8);
        System.out.println(i);
    }

在这里插入图片描述

    @Test
    public void testDeleteByMap(){
        Map<String, Object> map = new HashMap<>();
        map.put("name","提姆");
        map.put("age",22);
        int i = userMapper.deleteByMap(map);
        System.out.println(i);
    }

在这里插入图片描述

updateXXX更新数据

    @Test
    public void testUpdate(){
        //把id为2的用户的年龄改为14
        User user = new User();
        user.setId(2L);
        user.setAge(14);
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

在这里插入图片描述

(查询)条件构造器

在这里插入图片描述

在其子类AbstractWrapper中提供了很多用于构造Where条件的方法。
AbstractWrapper的子类QueryWrapper则额外提供了用于针对Select语法的select方法。可以用来设置查询哪些列。
AbstractWrapper的子类UpdateWrapper则额外提供了用于针对SET语法的set方法。可以用来设置对哪些列进行更新。

常用AbstractWrapper方法:

eq:equals,等于
gt:greater than ,大于 >
ge:greater than or equals,大于等于≥
lt:less than,小于<
le:less than or equals,小于等于≤
between:相当于SQL中的BETWEEN
like:模糊匹配。like("name","黄"),相当于SQL的name like '%黄%'
likeRight:模糊匹配右半边。likeRight("name","黄"),相当于SQL的name like '黄%'
likeLeft:模糊匹配左半边。likeLeft("name","黄"),相当于SQL的name like '%黄'
notLike:notLike("name","黄"),相当于SQL的name not like '%黄%'
isNull
isNotNull
and:SQL连接符AND
or:SQL连接符OR

in: in(“age",{1,2,3})相当于 age in(1,2,3)

groupBy: groupBy("id","name")相当于 group by id,name

orderByAsc :orderByAsc("id","name")相当于 order by id ASC,name ASC

orderByDesc :orderByDesc ("id","name")相当于 order by id DESC,name DESC

AbstractWrapper的子类QueryWrapper来实现
数据库:
在这里插入图片描述
示例一:大于等于

SELECT 
	id,user_name,PASSWORD,NAME,age,address 
FROM 
	USER 
WHERE 
	age > 18 AND address = '狐山'

Wrapper写法:

    @Test
    public void testWrapper01(){
        //实例构造器
        QueryWrapper wrapper = new QueryWrapper();
        //构造器添加条件(属性,条件)
        wrapper.gt("age",18);
        wrapper.eq("address","狐山");
        //使用构造器查询
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }

在这里插入图片描述
示例二:范围,排序

SELECT 
	id,user_name,PASSWORD,NAME,age,address 
FROM 
	USER 
WHERE 
	id IN(1,2,3) AND 
	age > 10 
ORDER BY 
	age DESC

Wrapper写法:

  @Test
    public void testWrapper03(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",1,2,3);
        queryWrapper.gt("age",18);
        queryWrapper.orderByDesc("age");
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }

在这里插入图片描述

常用QueryWrapper方法

QueryWrapper的 select 可以设置要查询的列。
示例一:要查询的列名

select(String… sqlSelect) 方法的测试为要查询的列名

SELECT 
	id,user_name
FROM 
	USER 

Wrapper写法:

    @Test
    public void testSelect01(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //select之后,要哪些字段,添加对应数据库列名
        queryWrapper.select("id","user_name");
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }

在这里插入图片描述

示例二:

select(Class entityClass, Predicate predicate),需要实体类对象

方法的第一个参数为实体类的字节码对象,第二个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。

SELECT 
	id,user_name
FROM 
	USER 

Wrapper写法:(对主键之外的数据)

 @Test
    public void testSelect02(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //实体类对象的字节码对象
        queryWrapper.select(User.class, new Predicate<TableFieldInfo>() {
            @Override
            public boolean test(TableFieldInfo tableFieldInfo) {
                return "user_name".equals(tableFieldInfo.getColumn());
            }
        });
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }


    @Test
    public void testSelect02(){
        //获取除主键之外,数据库字段为user_name的属性值
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(User.class, tableFieldInfo -> "user_name".equals(tableFieldInfo.getColumn()));
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }

在这里插入图片描述

示例三:

select(Predicate predicate),需要实体类对象

方法第一个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。

SELECT 
	id,user_name,PASSWORD,NAME,age 
FROM 
	USER

Wrapper写法:

    @Test
    public void testSelect03(){
    	//传入实体类对象
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(new User());
        queryWrapper.select(new Predicate<TableFieldInfo>() {
            @Override
            public boolean test(TableFieldInfo tableFieldInfo) {
                return !"address".equals(tableFieldInfo.getColumn());
            }
        });
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }

    @Test
    public void testSelect03(){
        //获取除主键之外,字段名不等于address的属性值
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(new User());
        queryWrapper.select(tableFieldInfo -> !"address".equals(tableFieldInfo.getColumn()));
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println(users);
    }

在这里插入图片描述

常用UpdateWrapper方法

使用update方法时需要创建一个实体类对象传入,用来指定要更新的列及对应的值。但是如果需要更新的列比较少时,创建这么一个对象显的有点麻烦和复杂。

​ 我们可以使用UpdateWrapper的set方法来设置要更新的列及其值。同时这种方式也可以使用Wrapper去指定更复杂的更新条件。
示例一:修改

UPDATE 
	USER
SET 
	age = 99
where 
	id > 1

Wrapper写法:

    @Test
    public void testUpdateWrapper(){
        //针对更新条件较复杂的
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        //匹配条件
        updateWrapper.gt("id",1);
        //设置值
        updateWrapper.set("age",99);
        updateWrapper.set("name","张三");
        userMapper.update(null,updateWrapper);
    }

在这里插入图片描述

Lambda条件构造器

前面在使用条件构造器时列名都是用字符串的形式去指定,这种方式无法在编译期确定列名的合法性。
Lambda条件构造器可以直接以实体类的方法引用的形式来指定列名,弥补上述缺陷。

SELECT 
	id,user_name,PASSWORD,NAME,age,address 
FROM 
	USER 
WHERE 
	age > 18 AND address = '狐山'

之前构造器方式:

    @Test
    public void testLambdaWrapper(){
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.gt("age",18);
        queryWrapper.eq("address","狐山");
        List<User> users = userMapper.selectList(queryWrapper);
    }

lambda构造器:

	//编译期间列名合法性,万一age写错,编译期间不报错,运行期间报错
    @Test
    public void testLambdaWrapper2(){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.gt(User::getAge,18);
        queryWrapper.eq(User::getAddress,"狐山");
        List<User> users = userMapper.selectList(queryWrapper);
    }

在这里插入图片描述

自定义SQL

支持Mybatis的方式去自定义方法,同时也支持在使用Mybatis的自定义方法时使用MP的条件构造器帮助我们进行条件构造。
1.准备sql

CREATE TABLE `orders` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `price` int(11) DEFAULT NULL COMMENT '价格',
  `remark` varchar(100) DEFAULT NULL COMMENT '备注',
  `user_id` int(11) DEFAULT NULL COMMENT '用户id',
  `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `version` int(11) DEFAULT '1' COMMENT '版本',
  `del_flag` int(1) DEFAULT '0' COMMENT '逻辑删除标识,0-未删除,1-已删除',
  `create_by` varchar(100) DEFAULT NULL COMMENT '创建人',
  `update_by` varchar(100) DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

/*Data for the table `orders` */

insert  into `orders`(`id`,`price`,`remark`,`user_id`,`update_time`,`create_time`,`version`,`del_flag`,`create_by`,`update_by`) values (1,2000,'无',2,'2021-08-24 21:02:43','2021-08-24 21:02:46',1,0,NULL,NULL),(2,3000,'无',3,'2021-08-24 21:03:32','2021-08-24 21:03:35',1,0,NULL,NULL),(3,4000,'无',2,'2021-08-24 21:03:39','2021-08-24 21:03:41',1,0,NULL,NULL);

2.实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Orders  {

    private Long id;

    /**
     * 价格
     */
    private Integer price;

    /**
     * 备注
     */
    private String remark;

    /**
     * 用户id
     */
    private Integer userId;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 版本
     */
    private Integer version;

    /**
     * 逻辑删除标识,0-未删除,1-已删除
     */
    private Integer delFlag;


}

3.Mapper接口中定义方法

public interface UserMapper extends BaseMapper<User> {

    User findMyUser(Long id);
}

4.配置xml文件的存放目录:

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

5.在xml中编写sql

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sangeng.mapper.UserMapper">

    <select id="findMyUser" resultType="com.sangeng.domian.User">
       select * from user where id = #{id} 
    </select>
</mapper>

6.测试

    @Test
    public void testSelect04(){
        User myUser = userMapper.findMyUser(1L);
        System.out.println(myUser);
    }

在这里插入图片描述

Mybatis方式结合条件构造器

1.方法中添加Warpper类型的参数,并指定参数名(默认ew)

public interface UserMapper extends BaseMapper<User> {

    User findMyUserByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

2.在xml中拼接sql

    <select id="findMyUserByWrapper" resultType="com.suisui.entity.User">
        select * from user ${ew.customSqlSegment}
    </select>

在这里插入图片描述

分页查询

基本分页查询

1.配置分页查询拦截器

@Configuration
public class MybatisPulsConfig {
    /**
     * 3.4.0之前的版本
     * @return
     */
   /* @Bean
    public PaginationInterceptor paginationInterceptor(){
        return  new PaginationInterceptor();
    }*/

    /**
     * 3.4.0之后版本
     * @return
     */
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor(){
       MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
       mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
       return mybatisPlusInterceptor;
   }
}

2.进行分页查询

    @Test
    public void testPage(){
        IPage<User> page = new Page<>();
        //设置每页条数
        page.setSize(2);
        //设置查询第几页
        page.setCurrent(1);
        //mp定义好的,只能用于单表
        userMapper.selectPage(page, null);
        System.out.println(page.getRecords());//获取当前页的数据
        System.out.println(page.getTotal());//获取总记录数
        System.out.println(page.getCurrent());//当前页码
    }

在这里插入图片描述

多表分页查询

分页配置同上,数据准备三更草堂视频
示例:查询orders表,还要求查询每个订单的下单用户的用户名。
1.在mapper接口中自定义方法,让方法接收Page对象

public interface OrdersMapper extends BaseMapper<Orders> {

    IPage<Orders> findAllOrders(Page<Orders> page);
}

2.在xml中不需要关心分页操作,MP会帮我们完成

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sangeng.mapper.OrdersMapper">
    <select id="findAllOrders" resultType="com.sangeng.domian.Orders">
        SELECT
            o.*,u.`user_name`
        FROM
            USER u,orders o
        WHERE
            o.`user_id` = u.`id`
    </select>
</mapper>

3.调用方法测试

    @Autowired
    private OrdersMapper ordersMapper;
    @Test
    public void testOrdersPage(){
        Page<Orders> page = new Page<>();
        //设置每页大小
        page.setSize(2);
        //设置当前页码
        page.setCurrent(2);
        ordersMapper.findAllOrders(page);
        System.out.println(page.getRecords());
        System.out.println(page.getTotal());
    }

在这里插入图片描述

Service接口

Service层更多支持批量操作
1.接口extends Iservice<实体类>

public interface UserService extends IService<User> {
    User test();
}

2.实现类extends ServiceImpl<Mapper接口,实体类> implements 接口

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

	//获取其他类的mapper接口
    @Autowired
    private OrdersMapper ordersMapper;

    @Override
    public User test() {
       //获取自己的mapper接口
        UserMapper userMapper = getBaseMapper();
        List<Orders> orders = ordersMapper.selectList(null);
        User user = userMapper.selectById(3);
        //查询用户对于的订单
        QueryWrapper<Orders> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",3);
        List<Orders> ordersList = ordersMapper.selectList(wrapper);
        return user;
    }
}

代码生成器

一键生成实体类,Mapper接口,Service,Controller等全套代码
1.添加依赖

 <!--mybatisplus代码生成器-->
 <dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-generator</artifactId>
   <version>3.4.1</version>
 </dependency>
 <!--模板引擎-->
 <dependency>
   <groupId>org.freemarker</groupId>
   <artifactId>freemarker</artifactId>
</dependency>

2.编写类,修改相应配置

public class GeneratorTest {
	@Test
	public void generate() {
		AutoGenerator generator = new AutoGenerator();

		// 全局配置
		GlobalConfig config = new GlobalConfig();
		String projectPath = System.getProperty("user.dir");
		// 设置输出到的目录
		config.setOutputDir(projectPath + "/src/main/java");
		config.setAuthor("sangeng");
		// 生成结束后是否打开文件夹
		config.setOpen(false);

		// 全局配置添加到 generator 上
		generator.setGlobalConfig(config);

		// 数据源配置
		DataSourceConfig dataSourceConfig = new DataSourceConfig();
		dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mp?characterEncoding=utf-8&serverTimezone=UTC");
		dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
		dataSourceConfig.setUsername("root");
		dataSourceConfig.setPassword("12345678");

		// 数据源配置添加到 generator
		generator.setDataSource(dataSourceConfig);

		// 包配置, 生成的代码放在哪个包下
		PackageConfig packageConfig = new PackageConfig();
		packageConfig.setParent("com.sangeng.mp.generator");

		// 包配置添加到 generator
		generator.setPackageInfo(packageConfig);

		// 策略配置
		StrategyConfig strategyConfig = new StrategyConfig();
		// 下划线驼峰命名转换
		strategyConfig.setNaming(NamingStrategy.underline_to_camel);
		strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
		// 开启lombok
		strategyConfig.setEntityLombokModel(true);
		// 开启RestController
		strategyConfig.setRestControllerStyle(true);
		generator.setStrategy(strategyConfig);
		generator.setTemplateEngine(new FreemarkerTemplateEngine());

        // 开始生成
		generator.execute();
	}
}

文件位置及日志打印:
在这里插入图片描述
在这里插入图片描述

自动填充(创建时间创建用户)

1.在实体类的对应字段上增加注解

  /**
     * 更新时间,在修改的时候自动填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    /**
     * 创建时间,在新增的时候自动填充
     */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

2.自定义填充处理器,implements MetaObjectHandler重写方法

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    String format = "YYYY-MM-dd HH:mm:ss";//24小时制,hh12小时制
    @Override
    public void insertFill(MetaObject metaObject) {
        Long userId = null;
        //注册时,还没有token
        try {
            userId = SecurityUtils.getUserId();
        } catch (Exception e) {
            e.printStackTrace();
            userId = -1L;//表示是自己创建
        }
        this.setFieldValByName("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)), metaObject);
        this.setFieldValByName("createBy",userId , metaObject);
        this.setFieldValByName("updateTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)), metaObject);
        this.setFieldValByName("updateBy", userId, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)), metaObject);
        this.setFieldValByName(" ", SecurityUtils.getUserId(), metaObject);
    }
}

注意数据库与实体类,数据类型保持一致
在这里插入图片描述

逻辑删除

3.3.0版本之前需要在对应字段上加@TableLogic注解

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: delFlag 
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

代码测试:

实体类属性:
    /**
     * 逻辑删除标识,0-未删除,1-已删除
     */
    private Integer delFlag;
测试删除:
    @Test
    public void testDeleteById(){
        int i = ordersMapper.deleteById(3);
        System.out.println(i);
    }
测试查询:
    @Test
    public void testDelete02(){
        ordersMapper.selectList(null);
    }

在这里插入图片描述
在这里插入图片描述

乐观锁

乐观锁就是先加上不存在并发冲突问题,在进行实际数据操作的时候再检查是否冲突。
在表中增加一个version列,用来记录每条记录操作的版本。每次对每条记录进行操作时,对应的版本也需要+1。
如果在查询老版本号到更新操作的中间时刻有其他人更新了这条数据,这次更新语句就会更新失败。
1.配置对应插件

@Configuration
public class MybatisPlusConfig {
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
    
    /**
     * 新版
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

2.在实体类的字段上加@Version注解

@Version
private Integer version;

3.更新:在更新前一定要先查询到version设置到实体类上再进行更新才能生效

    @Test
    public void testVersion(){
        //查询id为3的数据
        QueryWrapper<Orders> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",3);
        Orders orders = ordersMapper.selectOne(queryWrapper);
        
        //对id为3的数据进行更新  把price修改为88
        orders.setPrice(88);
        ordersMapper.updateById(orders);
    }

在这里插入图片描述

多插件配置问题

需要用到多个插件的话要注意,在配置的时候只需要注入一个MybatisPlusInterceptor 对象,把插件对象添加到MybatisPlusInterceptor 对象中即可。
顺序:

  • 多租户,动态表明
  • 分页,乐观锁
  • sql性能规范,防止全表更新与删除
  • 对sql进行单次改造的优先放入,不对sql进行改造的最后放入
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

版权声明:本文为weixin_43994244原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_43994244/article/details/126605589