当前位置: 首页 > news >正文

天津市武清区建设银行网站/湖南百度推广公司

天津市武清区建设银行网站,湖南百度推广公司,手机网站制作多少钱,山西建站便宜01、Mybatis-Plus入门 一、简介 MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。如果你想对自己的项目进行技术升级,不妨尝试将mybatis换成Mybati…

01、Mybatis-Plus入门

一、简介

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。如果你想对自己的项目进行技术升级,不妨尝试将mybatis换成Mybatis-Plus,你将从此在无比强大的mp大法中沉迷而无法自拔日渐精神!mp 润物无声,只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。并且mp 遵循效率至上,你只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。同时mp拥有 丰富的功能,热加载、代码生成、分页、性能分析等功能一应俱全。让我们从本篇出发,开启真正的mp开发之旅吧!
在这里插入图片描述

二、创建并初始化数据库

为了更加清晰直观地进行讲解,这里我们使用Navicat,创建了mp_practice数据库,同时在数据库中创建了User表,并将初始数据添加

1、创建数据库

在这里插入图片描述

2、创建User表

(1)对应的数据库 Schema 脚本如下:

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

(2)对应的数据库 Data 脚本如下:

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

最后在Navicat中结果呈:
在这里插入图片描述

三、创建项目

1、初始化工程

使用 Spring Initializr 快速初始化一个 Spring Boot 工程
在这里插入图片描述
settings中将group,artifact,type,Java Version,name换成自己需要的
在这里插入图片描述
在这里插入图片描述

2、引入依赖

在pom.xml文件中引入依赖

<dependencies><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><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!--mysql运行时依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--lombok用来简化实体类--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis,以避免因版本差异导致的问题。

3、在idea中安装lombok插件

不同版本安装lombok插件方式不同,可以根据自己idea的版本在csdn中搜索自己对应版本的lombok插件安装方法(博主自己的2019版本当初在安装的时候出现过应用商店没有对应版本的lombok的问题,大体解决思路是去官网下载lombok包然后导入本地,可参照此博客)

四、代码

1、配置

springboot默认建立的就是application.properties,直接在 application.properties 配置文件中添加 MySQL 数据库的相关配置:

(1)spring boot 2.0(内置jdbc5驱动)

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp_practice?characterEncoding=utf-8&useSSL=false
spring.datasource.username=你的username
spring.datasource.password=你的password

(2)spring boot 2.1及以上(内置jdbc8驱动)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp_practice?serverTimezone=GMT%2B8
spring.datasource.username=你的username
spring.datasource.password=你的password	

注意:
1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息

2、主类

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

@SpringBootApplication
@MapperScan("com.xuhao.mp.mapper")
public class MybatisPlusApplication {......
}

3、实体

创建报entity编写实体类User.java(此处使用lombok的@Data)

@Data//自动生成对应的实体类如get、set、equals、hashCode、toString等方法
public class User {private Long id;//Long切勿写成longprivate String name;private Integer age;private String email;
}

在这里插入图片描述

4、接口

创建包mapper编写Mapper接口:UserMapper.java

 package com.xuhao.mp.mapper;/*@author: 徐昊@since: 2023/3/5*/import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xuhao.mp.entity.User;public interface UserMapper extends BaseMapper<User> {
}

5、测试

在这里插入图片描述

此时红色波浪线并不代表出现错误,在UserMapper中使用@Repository注解即可

在这里插入图片描述

此时红色波浪线消失(强迫症狂喜)

在这里插入图片描述

编写测试方法:

    @Testvoid testSelectList(){List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}

控制台打印出如下内容,查询成功
在这里插入图片描述

02、CURD接口-主键策略

一、插入操作

    @Testpublic void testInsert(){User user = new User();user.setName("xubanxian");user.setEmail("1008611@qq.com");user.setAge(8848);int result = userMapper.insert(user);//返回值为影响的行数System.out.println("影响的行数为:"+result);System.out.println("user id:"+user.getId());}

这里我们并未对id进行赋值但是却由于mp的主键策略,自动生成了一个全局唯一id在这里插入图片描述
那么,生成了这么长的一个id到底有什么意义呢?

二、数据库分库分表策略

背景:

随着业务规模的不断扩大,需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。数据库的扩展方式主要包括:业务分库、主从复制,数据库分表

1、业务分库

业务分库指的是按照业务模块将数据分散到不同的数据库服务器。例如,一个简单的电商网站,包括用户、商品、订单三个业务模块,我们可以将用户数据、商品数据、订单数据分开放到三台不同的数据库服务器上,而不是将所有数据都放在一台数据库服务器上。这样的就变成了3个数据库同时承担压力,系统的吞吐量自然就提高了。
在这里插入图片描述
虽然业务分库能够分散存储和访问压力,但同时也带来了新的问题:

(1)join 操作问题
业务分库后,原本在同一个数据库中的表分散到不同数据库中,导致无法使用 SQL 的 join 查询。
(2)事务问题
原本在同一个数据库中不同的表可以在同一个事务中修改,业务分库后,表分散到不同的数据库中,无法通过事务统一修改。
(3)成本问题
业务分库同时也带来了成本的代价,本来 1 台服务器搞定的事情,现在要 3 台,如果考虑备份,那就是 2 台变成了 6 台

2、主从复制和读写分离

读写分离的基本原理是将数据库读写操作分散到不同的节点上。读写分离的基本实现是:

数据库服务器搭建主从集群,一主一从、一主多从都可以。 数据库主机负责读写操作,从机只负责读操作。
数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。 业务服务器将写操作发给数据库主机,将读操作发给数据库从机。
在这里插入图片描述

注意:
这里用的是“主从集群”,而不是“主备集群”。
“从机”的“从”可以理解为“仆从”,仆从是要帮主人干活的,“从机”是需要提供读数据的功能的;
而“备机”一般被认为仅仅提供备份功能,不提供访问功能。
所以使用“主从”还是“主备”,是要看场景的,这两个词并不是完全等同。

3、数据库分表(重点)

将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如,淘宝的几亿用户数据,如果全部存放在一台数据库服务器的一张表中,肯定是无法满足性能要求的,此时就需要对单表数据进行拆分。
在这里插入图片描述

(1)分表方式

①、垂直分表

垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。
例如,前面示意图中的 nickname 和 description字段,假设我们是一个婚恋网站,用户在筛选其他用户的时候,主要是用 age 和 sex 两个字段进行查询,而 nickname 和description 两个字段主要用于展示,一般不会在业务查询中用到。description本身又比较长,因此我们可以将这两个字段独立到另外一张表中,这样在查询 age 和 sex 时,就能带来一定的性能提升。

②、水平分表

水平分表适合表行数特别大的表,有的公司要求单表行数超过 5000 万就必须进行分表,这个数字可以作为参考,但并不是绝对标准,关键还是要看表的访问性能。对于一些比较复杂的表,可能超过 1000 万就要分表了;而对于一些简单的表,即使存储数据超过 1 亿行,也可以不分表。
但不管怎样,当看到表的数据量达到千万级别时,作为架构师就要警觉起来,因为这很可能是架构的性能瓶颈或者隐患。

(2)策略

水平分表相比垂直分表,会引入更多的复杂性,例如数据id,一般有以下几种策略:

①、主键自增

以最常见的用户 ID 为例:
按照 1000000 的范围大小进行分段,1 ~ 999999 放到表 1中,1000000 ~ 1999999 放到表2中,以此类推。

复杂点: 分段大小的选取。分段太小会导致切分后子表数量过多,增加维护复杂度;分段太大可能会导致单表依然存在性能问题,一般建议分段大小在 100 万2000 万之间,具体需要根据业务选取合适的分段大小。
优点: 可以随着数据的增加平滑地扩充新的表。例如,现在的用户是 100 万,如果增加到 1000 万,只需要增加新的表就可以了,原有的数据不需要动。
缺点: 分布不均匀,假如按照 1000 万来进行分表,有可能某个分段实际存储的数据量只有 1000 条,而另外一个分段实际存储的数据量有 900 万条。

②、Hash策略

同样以用户 ID 为例:
假如我们一开始就规划了 10 个数据库表,路由算法可以简单地用 user_id % 10 的值来表示数据所属的数据库表编号,ID 为 985 的用户放到编号为 5 的子表中,ID 为 10086 的用户放到编号为 6 的字表中。

复杂点: 初始表数量的选取。表数量太多维护比较麻烦,表数量太少又可能导致单表性能存在问题。
优点: 表分布比较均匀。
缺点: 扩充新的表很麻烦,所有数据都要重分布。

③、雪花算法

雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性
核心思想:
a、长度共64bit(一个long型)。
b、首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
c、41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
d、10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
e、12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

在这里插入图片描述

三、MP的主键策略

进入原码中我们发现mp的主键策略中有如下多个策略
在这里插入图片描述

1、ASSIGN_ID

MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)

@TableId(type = IdType.ASSIGN_ID)
private String id;

2、AUTO自增策略

需要在创建数据表的时候设置主键自增
实体字段中配置 @TableId(type = IdType.AUTO)

@TableId(type = IdType.AUTO)
private Long id;

3、全局主键配置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

03、CURD接口-自动填充和乐观锁

一、更新

    @Testpublic void testUpdateById(){User user = new User();user.setId(1L);user.setAge(28);int result = userMapper.updateById(user);System.out.println("影响行数:"+result);}

注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?

二、自动填充

应用场景:

在未使用自动填充之前,相应的insert和update方法应该如下:

    @Testpublic void testInsert(){User user = new User();user.setName("xubanxian");user.setEmail("1008611@qq.com");user.setAge(8867);user.setCreateTime(new Date());user.setUpdateTime(new Date());int result = userMapper.insert(user);//返回值为影响的行数System.out.println("影响的行数为:"+result);System.out.println("user id:"+user.getId());}@Testpublic void testUpdateById(){User user = new User();user.setId(1L);user.setAge(28);user.setUpdateTime(new Date());int result = userMapper.updateById(user);System.out.println("影响行数:"+result);}
}

每一次更新我们都要对相应的时间进行代码编写,这实在是太麻烦了。所幸,mp给我们提供了非常方便的代码填充插件,mp真的太懂程序员了!

需求:

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作

1、修改数据库

在User表中添加datetime类型的新的字段create_time、update_time

2、实体类修改

@Data
public class User {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;//mp会自动将驼峰转化成数据库对应的下划线的形式@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;
}

3、实现元对象处理器接口

package com.atguigu.mybatisplus.handler;@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insert fill ....");this.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {log.info("start update fill ....");this.setFieldValByName("updateTime", new Date(), metaObject);}
}

三、乐观锁

1、场景

  一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。
  此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。
  现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1多万。

2、悲观锁与乐观锁

  上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。

  如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。

3、模拟修改冲突

(1)数据库中增加商品表

CREATE TABLE product
(id BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',price INT(11) DEFAULT 0 COMMENT '价格',version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',PRIMARY KEY (id)
);

(2)添加数据

INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);

(3)实体类

package com.atguigu.mybatis_plus.entity;
@Data
public class Product {private Long id;private String name;private Integer price;private Integer version;
}

(4)Mapper

package com.atguigu.mybatis_plus.mapper;
@Repository
public interface ProductMapper extends BaseMapper<Product> {}

(5)模拟测试

@Autowired
private ProductMapper productMapper;/*** 并发编程一般叫concurrent*/
@Test
public void testConcurrentUpdate() {//1、小李Product p1 = productMapper.selectById(1L);System.out.println("小李取出的价格:" + p1.getPrice());//2、小王Product p2 = productMapper.selectById(1L);System.out.println("小王取出的价格:" + p2.getPrice());//3、小李将价格加了50元,存入了数据库p1.setPrice(p1.getPrice() + 50);productMapper.updateById(p1);//4、小王将商品减了30元,存入了数据库p2.setPrice(p2.getPrice() - 30);int result = productMapper.updateById(p2);if(result == 0){//更新失败,重试//重新获取数据p2 = productMapper.selectById(1L);//更新p2.setPrice(p2.getPrice() - 30);productMapper.updateById(p2);}//最后的结果Product p3 = productMapper.selectById(1L);System.out.println("最后的结果:" + p3.getPrice());
}

4、解决方案

  • 数据库中添加version字段

  • 取出记录时,获取当前version SELECT id,name,version FROM product WHERE id=1

  • 更新时,version + 1,如果where语句中的version版本不对,则更新失败

  • UPDATE product SET price=price+50, version=version+ 1 WHERE id=1 AND version=1

接下来介绍如何在Mybatis-Plus项目中,使用乐观锁:

5、乐观锁实现流程

(1)修改实体类

添加 @Version 注解

@Data
public class Product {private Long id;private String name;private int price;@Versionprivate int version;
}

(2)创建配置文件

创建包config,创建文件MybatisPlusConfig.java,我们从此之后将对mp的配置全部集中在这个类中实现,此时可以删除主类中的 @MapperScan 扫描注解

@EnableTransactionManagement//事务处理
@Configuration
@MapperScan("com.xuhao.mp.mapper")
public class MyBatisPlusConfig {}

(3)注册乐观锁插件

在 MybatisPlusConfig 中注册 Bean

    /*** 乐观锁插件*/@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}

(4)测试

    /*** 并发编程一般叫concurrent*/@Testpublic void testConcurrentUpdate(){
//        1、小李获取数据Product product1 = productMapper.selectById(1L);System.out.println("小李去除的价格"+product1.getPrice());//        2、小王获取数据Product product2 = productMapper.selectById(1L);System.out.println("小王获取的数据"+product2.getPrice());//        3、小李加了50存入数据库product1.setPrice(product1.getPrice()+50);productMapper.updateById(product1);//        4、小王减了30存入数据库product2.setPrice(product2.getPrice()-30);int result = productMapper.updateById(product2);//若更新失败,result为0if (result == 0){System.out.println("小王更新失败");//发起重试product2 = productMapper.selectById(1L);product2.setPrice(product2.getPrice() - 30);productMapper.updateById(product2);}//        5、输出结果Product product3 = productMapper.selectById(1L);System.out.println("最后的结果:"+product3.getPrice());}

04、查询和分页

一、查询

1、通过多个id批量查询

    @Testpublic void testSelectBatchIds(){List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));users.forEach(System.out::println);}

2、简单的条件查询

通过map封装查询条件

    /*** 最基本的条件查询*/@Testpublic void testSelectByMap(){HashMap<String, Object> map = new HashMap<>();map.put("name","xubanxian");map.put("age",18);List<User> users = userMapper.selectByMap(map);for (User user : users) {System.out.println(user);}}

对应的sql语句:
SELECT id,name,age,email,create_time,update_time FROM user WHERE name = ? AND age = ?

注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id

二、分页

1、分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

(1)添加分页插件

配置类中添加@Bean配置

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

(2)测试selectPage分页

测试: 最终通过 page 对象获取相关数据

    @Testpublic void testSelectPage(){//第一页,每页五条记录Page<User> page = new Page<>(1, 5);//queryWrapper,条件构造器Page<User> pageParam = userMapper.selectPage(page, null);List<User> records = pageParam.getRecords();records.forEach(System.out::println);System.out.println(pageParam.getCurrent());//当前页码System.out.println(pageParam.getPages());//总页数System.out.println(pageParam.getSize());//每页记录数System.out.println(pageParam.getTotal());//总记录数System.out.println(pageParam.hasNext());//是否有下一页System.out.println(pageParam.hasPrevious());//是否上一页}

对应的sql语句:SELECT id,name,age,email,create_time,update_time FROM user LIMIT 0,5

2、返回指定的列

当指定了特定的查询列时,希望分页结果列表只返回被查询的列,而不是很多null值
测试selectMapsPage分页:结果集是Map

@Test
public void testSelectMapsPage() {//返回很多null列//Page<User> page = new Page<>(1, 5);//QueryWrapper<User> queryWrapper = new QueryWrapper<>();//queryWrapper.select("name", "age");//Page<User> pageParam = userMapper.selectPage(page, queryWrapper);////pageParam.getRecords().forEach(System.out::println);//条件构造器QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.select("id","name");//只查id和name,//SELECT id,name FROM user LIMIT ?,?//第一页,每页五条记录Page<Map<String,Object>> page = new Page<>(1, 5);//queryWrapper,条件构造器Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, userQueryWrapper);List<Map<String, Object>> records = page.getRecords();records.forEach(System.out::println);System.out.println(pageParam.getCurrent());System.out.println(pageParam.getPages());System.out.println(pageParam.getSize());System.out.println(pageParam.getTotal());System.out.println(pageParam.hasNext());System.out.println(pageParam.hasPrevious());
}

05、CURD接口-删除和逻辑删除

一、删除

1、根据id删除记录

@Test
public void testDeleteById(){int result = userMapper.deleteById(5L);System.out.println(result);
}

2、批量删除

    @Testpublic void testDeleteBatchById(){int result = userMapper.deleteBatchIds(Arrays.asList(7, 8, 9, 10));System.out.println("删除了:"+result+"行");}

3、简单条件删除

    @Testpublic void testDeleteByMap(){HashMap<String, Object> map = new HashMap<>();map.put("name","xubanxian");map.put("age",18);int result = userMapper.deleteByMap(map);System.out.println("删除了:"+result+"行");}

二、逻辑删除

1、物理删除和逻辑删除

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除的使用场景:

  • 可以进行数据恢复
  • 有关联数据,不便删除

2、逻辑删除实现流程

(1)数据库修改

添加 deleted字段:ALTER TABLE user ADD COLUMN deleted boolean DEFAULT false

(2)实体类修改

添加deleted 字段,并加上 @TableLogic 注解

@Data
public class User {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;//mp会自动将驼峰转化成数据库对应的下划线的形式@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;@TableLogic	//逻辑删除标记private Integer deleted;
}

(3)配置(可选)

application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无

#被删除时为1
mybatis-plus.global-config.db-config.logic-delete-value=1
#未被删除时为0
mybatis-plus.global-config.db-config.logic-not-delete-value=0

(4)测试

逻辑删除的本质是对delete进行修改,语句为:
UPDATE user SET deleted=1 WHERE id=? AND deleted=0

  • 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
  • 测试后分析打印的sql语句,是一条update
  • 注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作(因为sql内同时对deleted的值进行判断,若为1则直接不执行update,这样可以节省运行时间)
//logic为逻辑的意思
@Test
public void testLogicDelete() {int result = userMapper.deleteById(1L);System.out.println(result);
}

Navicat内观察结果:

在这里插入图片描述

(5)测试逻辑删除后的查询

MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断:
SELECT id,name,age,email,create_time,update_time,deleted FROM user WHERE deleted=0

@Test
public void testLogicDeleteSelect() {List<User> users = userMapper.selectList(null);users.forEach(System.out::println);
}

控制台运行结果如下:

在这里插入图片描述

3、有趣的发现(可能是bug)

偶然发现,mp在进行逻辑删除的时候不会触发mp的自动填充(目前还不知道是因为啥),问题如下:

在最刚开始时候在这里插入图片描述id为11的xubanxian的update_time是2023-03-07 21:37:19,此时这个xubanxian的deleted为0,处于非逻辑删除状态。
在这里插入图片描述
在上图这个时间的时候博主运行了逻辑删除测试方法,

在这里插入图片描述
测试方法运行成功后,deleted状态变为1,此时的11号xubanxian为逻辑删除状态,但是原本应该被自动填充的update_time为实现自动填充,着实怪哉!
在这里插入图片描述
目前查到的一个原因好像是低版本的mp会出现这种bug,换成新版本的好像会解决这个bug。
真正的原因目前还没查明白QAQ(不知道屏幕前的你遇没遇到过这种问题,如果有合理的解决方案请发到评论区,万分感谢!)

06、条件构造器和常用接口

一、wapper介绍

在这里插入图片描述

Wrapper : 条件构造抽象类,最顶端父类
 AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
   QueryWrapper : 查询条件封装(用的最多)
   UpdateWrapper : Update 条件封装
 AbstractLambdaWrapper : 使用Lambda 语法
  LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper(复杂的会用到)
  LambdaUpdateWrapper : Lambda 更新封装Wrapper

为了更加清晰地演示,这里博主创建了一个新的测试类

@SpringBootTest
public class QueryWrapperTests {@Autowiredprivate UserMapper userMapper;
}

二、测试用例

1、ge、gt、le、lt、isNull、isNotNull

    @Testpublic void testDelete(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        链式编程queryWrapper.eq("age",8858).isNotNull("email").isNotNull("name");
//        queryWrapper.ge("age",18);//大于等于18
//        queryWrapper.gt("age",18);//大于18
//        queryWrapper.le("age",18);//小于等于18
//        queryWrapper.lt("age",18);//下于18int delete = userMapper.delete(queryWrapper);System.out.println("删除了"+delete+"行");}

2、eq、ne

    @Testpublic void testSelectOne(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name","Tom");User user = userMapper.selectOne(queryWrapper);//只能返回一条记录,多余一条则抛出异常System.out.println(user);}

sql:SELECT id,name,age,email,create_time,update_time,deleted FROM user WHERE deleted=0 AND (name = ?)

结果:
在这里插入图片描述

注意:selectOne()返回的是一条实体记录,当出现多条时会报错
   selectOne()可以用于账号的是否唯一的检查中

3、between、notBetween

包含大小边界

    @Testpublic void testSelectCount(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.between("age",10,30);List<User> users = userMapper.selectList(queryWrapper);Integer count = userMapper.selectCount(queryWrapper);System.out.println("年纪在10-30的有"+count+"人");System.out.println("分别是:");users.forEach(System.out::println);}

sql:SELECT COUNT( 1 ) FROM user WHERE deleted=0 AND (age BETWEEN ? AND ?)

结果:
在这里插入图片描述

4、like、notLike、likeLeft、likeRight

selectMaps()返回Map集合列表,通常配合select()使用

    @Testpublic void testSelectMaps(){QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("name","age").like("name","e").likeRight("email","t");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}

sql: SELECT name,age FROM user WHERE deleted=0 AND (name LIKE ? AND email LIKE ?)
Parameters: %e%(String), t%(String)

结果:
在这里插入图片描述

5、in、notIn、inSql、notinSql、exists、notExists

待更新

6、or、and

待更新

7、lambda表达式

待更新

8、orderBy、orderByDesc、orderByAsc

待更新

9、set、setSql

待更新

三、 查询方式汇总

在这里插入图片描述

07、mp实战讲解分析

更新未完待续……
未来博主会继续将项目中遇到的一些比较好的mp实战代码进行讲解分析,并更新在这一篇博客中,诸君共勉!

相关文章:

Mybatis-Plus学透?一篇足够(持续更新中)

01、Mybatis-Plus入门 一、简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。如果你想对自己的项目进行技术升级&#xff0c;不妨尝试将mybatis换成Mybati…...

船用燃料油市场调研报告-主要企业、市场规模、份额及发展趋势

船用燃料油市场报告主要研究&#xff1a;市场规模&#xff1a; 产能、产量、销售、产值、价格、成本、利润等行业分析&#xff1a;原材料、市场应用、产品种类、市场需求、市场供给&#xff0c;下游市场分析、供应链分析等竞争分析&#xff1a;主要企业情况、市场份额、并购、扩…...

python趣味编程-奥赛罗游戏

在上一期我们用Python实现了一个高速公路汽车游戏的游戏&#xff0c;这一期我们继续使用Python实现一个简单的奥赛罗游戏&#xff0c;让我们开始今天的旅程吧~ 在Python中使用Turtle实现的奥赛罗游戏 在Python中使用Turtle的简单奥赛罗游戏 是一个以 Python 为程序设计语言的项…...

经典卷积模型回顾13—ResNetXt实现图像分类(matlab)

ResNetXt是ResNet的变种&#xff0c;在ResNet基础上引入了"split-transform-merge"的思想&#xff0c;旨在进一步提升模型的性能和准确率。ResNetXt模型的核心思想是通过对输入进行分组&#xff0c;然后对每个分组进行不同的变换&#xff0c;最后再将变换后的结果合并…...

Spring学习——Maven进阶

分模块开发与设计 创建模块 书写模块代码 通过maven指令安装模块到本地仓库(install指令) 在pom.xml中导入坐标执行maven的install命令将模块安装到本地maven仓库 团队内部开发可以发布模块功能到团队内部可共享的仓库中&#xff08;私服) 依赖管理 依赖指当前项目运行所需…...

第23篇:基础知识-Java Switch Case

switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。 switch case 语句语法格式如下: switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的…...

Go 实现多态和 参数的动态个数及动态类型

引子 go语言作为静态(编译期类型检测)强类型(手写代码进行类型转换)语言, 要想实现 动态语言的鸭子类型的调用方法,做到 一个入参是不同类型,还是有些麻烦的; 需求 希望写代码时像python一样的鸭子类型,不用管参数类型,都可以调用同一个方法;希望 入参像python一样 能够在 个…...

vue 指令

Vue 提供了很多指令&#xff0c;如&#xff1a;v-model, v-show&#xff0c;v-if等等&#xff0c;有利于应付开发时出现的各种情况。Vue 也提供了自定义指令&#xff0c;有利于开发者将某些通用性功能封装成一个指令&#xff0c;进行全局或局部注册。如&#xff1a;复制指令&am…...

APP违法违规收集使用个人信息合规评流程和范围

近期&#xff0c;工信部通报2023年第1批《侵害用户权益行为的APP通报》&#xff08;总第27批&#xff09;&#xff0c;共通报46款APP&#xff08;SDK&#xff09;&#xff0c;这些被责令限期整改的APP&#xff08;SDK&#xff09;&#xff0c;涉及的问题主要包括3个方面&#x…...

【力扣2379】 得到 K 个黑块的最少涂色次数(c++100%)

给你一个长度为 n 下标从 0 开始的字符串 blocks &#xff0c;blocks[i] 要么是 W 要么是 B &#xff0c;表示第 i 块的颜色。字符 W 和 B 分别表示白色和黑色。给你一个整数 k &#xff0c;表示想要 连续 黑色块的数目。每一次操作中&#xff0c;你可以选择一个白色块将它 涂成…...

[2.2.2]进程调度的时机、方式、切换与过程

文章目录第二章 进程管理进程调度的时机、方式、切换与过程&#xff08;一&#xff09;进程调度的时机&#xff08;二&#xff09;进程调度的方式&#xff08;三&#xff09;进程的切换与过程小结第二章 进程管理 进程调度的时机、方式、切换与过程 时机 什么时候需要进程调度…...

第24篇:Java包装类知识深度分析

目录 1、包装类背景 2、包装类的优点 3、包装类与基本类型关系 4、代码示例...

常见问题整理1

目录 偏差和方差 欠拟合underfitting 过拟合overfitting 梯度消失和梯度爆炸 归一化 偏差和方差 偏差&#xff1a;算法期望预测和真实预测之间的偏差程度。反应的是模型本身的拟合能力。 方差&#xff1a;度量了同等大小的训练集的变动导致学习性能的变化&#xff0c;刻画…...

体验Linux 块设备驱动实验(模拟块)

目录 一、块设备 二、块设备驱动框架 1、块设备的注册和注销 2、gendisk 结构体 3、block_device_operations 结构体 4、块设备 I/O 请求过程 ①、请求队列 request_queue ②、bio 结构 三、编写驱动之请求队列 1、修改makefile 2、基本的驱动框架​编辑 3、添加头文…...

一文搞懂Linux时区设置、自定义时区文件

概念介绍 常说的 Linux 系统时钟有两个 一个是硬件时钟&#xff08;RTC&#xff09;&#xff0c;即BIOS时间&#xff0c;一般保存的是 GMT0 时间&#xff0c;没时区、夏令时的概念 一个是当地时钟&#xff08;LTC&#xff09;&#xff0c;即我们日常经常看到的时间&#xff0…...

Java实例实验项目大全源码企业通讯打印系统计划酒店图书学生管理进销存商城门户网站五子棋

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;java实例 获取完整源码源文件视频讲解文档资料等 文章目录1、企业通讯2、快递打印系统3、开发计划管理系统4、酒店管理系统5、图书馆管理系统6、学生成绩管理系统7、进销存管理系统8、神奇Book——图书商城9、企业门户网站…...

基于nvidia xavier智能车辆自动驾驶域控制器设计与实现-百度Apollo架构(二)

智能车辆操作系统 智能车辆操作系统是智能车辆系统的重要组成部分。现代汽车软件组件通常首 先由不同的供应商开发&#xff0c;然后在有限的资源下由制造商进行集成[42]。智能车辆操作 系统需要采用模块化和分层化设计思想来兼容传感器、分布式通信和自动驾驶通用 框架等模块&a…...

考研408 王道计算机考研 (初试/复试) 网课笔记总结

计算机初试、复试笔记总结&#xff08;导航栏&#xff09;&#x1f4dd; 一、初试 408 408 - 1. 数据结构与算法 数据结构与算法 笔记导航&#x1f6a5;&#x1f6a5;&#x1f6a5; &#x1f96c; 第一章 绪论(无)&#x1f955; 第二章 线性表&#x1f96a; 第三章 栈和队列&…...

[Java·算法·中等]LeetCode34. 在排序数组中查找元素的第一个和最后一个位置

每天一题&#xff0c;防止痴呆题目示例分析思路1题解1&#x1f449;️ 力扣原文 题目 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1,…...

SAP BTEs的简介及实现

一、认识BTE BTE&#xff08;Business Transaction Event&#xff09;也称之为“业务交易事件”,一般的增强(Tcode:SMOD|CMOD)依旧使用ABAP进行二次开发,然而BTE则提供了RFC调用其它产品的可能(Tcode:FIBF)。BTE的设计思路更加简单&#xff0c;和BADI有点类似。在标准程序中留有…...

如何利用海外主机服务提高网站速度?

网站速度是任何在线业务成功的关键。快速的网站速度可以让用户更快地访问您的网站&#xff0c;增加页面浏览量。对于拥有全球用户的网站而言&#xff0c;选择一个海外主机服务商是提高网站速度的有效方法之一。下面是一些利用海外主机服务(如美国主机、香港主机)提高网站速度的…...

【SpringMVC】 一文掌握 》》》 @RequestMapping注解

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ RequestMapping注解一、SpringMVC环境准备1.相…...

高三应该怎么复习

高三是学生们备战高考的重要一年&#xff0c;正确有序的复习可以有效地提高复习效率&#xff0c;下面是一些高效复习的方法和建议&#xff1a;1. 制定合理的学习计划和目标高三的学生要制定合理的学习计划和目标&#xff0c;适当的计划和目标可以使学习更有针对性和效率。建议根…...

如何通过C++ 将数据写入 Excel 工作表

直观的界面、出色的计算功能和图表工具&#xff0c;使Excel成为了最流行的个人计算机数据处理软件。在独立的数据包含的信息量太少&#xff0c;而过多的数据又难以理清头绪时&#xff0c;制作成表格是数据管理的最有效手段之一。这样不仅可以方便整理数据&#xff0c;还可以方便…...

Kalman Filter in SLAM (6) ——Error-state Kalman Filter (EsKF, 误差状态卡尔曼滤波)

文章目录0.前言1. IMU的误差状态空间方程2. 误差状态观测方程3. 误差状态卡尔曼滤波4. 误差状态卡尔曼滤波方程细节问题0.前言 这里先说一句&#xff1a;什么误差状态卡尔曼&#xff1f;完全就是在扯淡&#xff01; 回想上面我们推导的IMU的误差状态空间方程&#xff0c;其实…...

centos7部署KVM虚拟化

目录 centos7部署KVM虚拟化平台 1、新建一台虚拟机 2、系统内的操作 1、修改主机名 2、挂载镜像光盘 3、ssh优化 4、设置本地yum仓库 5、关闭防火墙&#xff0c;selinux 3、安装KVM 4、设置KVM网络 5、KVM部署与管理 6、使用虚拟系统管理器管理虚拟机 创建存储池 …...

【华为机试真题详解 Python实现】最小施肥机能效【2023 Q1 | 100分】

文章目录 前言题目描述输入描述输出描述示例 1输入:输出:示例 2输入:输出:题目解析参考代码暴力解法二分法前言 《华为机试真题详解》专栏含牛客网华为专栏、华为面经试题、华为OD机试真题。 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可…...

SpringBoot - 什么是跨域?如何解决跨域?

什么是跨域&#xff1f; 在浏览器上当前访问的网站&#xff0c;向另一个网站发送请求&#xff0c;用于获取数据的过程就是跨域请求。 跨域&#xff0c;是浏览器的同源策略决定的&#xff0c;是一个重要的浏览器安全策略&#xff0c;用于限制一个 origin 的文档或者它加载的脚本…...

Astra pro相机使用说明

奥比中光的Astra pro这款相机&#xff0c;目前官网已经搜不到相关信息&#xff0c;应该是停产了。但是很多机器人设备上或者淘宝上还能买到。使用起来经常会出现不同的问题。问题1&#xff1a; 这款相机据网友描述&#xff0c;就是乐视相机LeTMC-520&#xff0c;换了外壳&#…...

扬帆优配|数字经济刮起“东风”,龙头晋级7连板

今日两市共40只涨停股&#xff0c;主要集中于数字经济、6G板块&#xff0c;上一个交易日涨停股为29股&#xff1b;除掉18只ST股及3只一字板新股&#xff0c;共19股涨停。另外&#xff0c;4股封板未遂&#xff0c;整体封板率为83%。 6股封单金额超亿元 从收盘涨停板封单量来看&…...