MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
快速开始 | MyBatis-Plus (baomidou.com)
创建数据库,创建数据库表
创建工程 springboot
可以使用 Spring Initializer (opens new window)快速初始化一个 Spring Boot 工程
引入依赖
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
配置数据库信息
spring:
datasource:
username: root
password: 123456
url: "jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8"
driver-class-name: com.mysql.cj.jdbc.Driver
编写实体类
User
package com.mj.demomptest.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper接口
UserMapper
package com.mj.demomptest.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mj.demomptest.entity.User;
public interface UserMapper extends BaseMapper<User> {
}
包扫描
package com.mj.demomptest;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.mj.demomptest.mapper")
/*
mapper 是一个interface接口动态生成实现类对象
动态生成对象默认找不到
@MapperScan 才能找到动态生成的对象
*/
public class DemomptestApplication {
public static void main(String[] args) {
SpringApplication.run(DemomptestApplication.class, args);
}
}
测试
package com.mj.demomptest;
import com.mj.demomptest.entity.User;
import com.mj.demomptest.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class DemomptestApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void findAll() {
System.out.println(userMapper.selectList(null));
}
}
查看sql输出日志
#mybatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
控制台输出

@Test
public void testAdd(){
User user = new User();
user.setName("Lucy");
user.setAge(20);
user.setEmail("09876@qq.com");
//返回影响行数
int insert = userMapper.insert(user);
System.out.println(insert);
}

//修改
@Test
public void testUpdate(){
User user = new User();
user.setId(1585808430935887874L);
user.setName("Mary");
int count = userMapper.updateById(user);
System.out.println(count);
}
//添加
@Test
public void testAdd() {
User user = new User();
user.setName("lucy");
user.setAge(20);
user.setEmail("1243@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
}
注意:数据库插入id值默认为:全局唯一id
1585808430935887874
MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)
@TableId(type = IdType.ASSIGN_ID)``private String id;
雪花算法:分布式ID生成器
雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
核心思想:
长度共64bit(一个long型)。
首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
需要在创建数据表的时候设置主键自增
实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;
要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
使用相同的方式填充
准备工作
在表中添加两个字段
添加datatime类型的新的字段,create_time,update_time
在表对应实体类添加对应的属性
实体类修改
自动填充属性添加注解
@TableField(fill = FieldFill.INSERT)
//添加的时候设置值
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
//添加的时候设置值,修改的时候不设置值
private Date updateTime;
创建实体类实现接口,实现接口两个方法
一个方法添加执行,一个方法修改执行
设置添加什么值
注意:不要忘记添加 @Component 注解
package com.mj.demomptest.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//mp执行添加操作时
@Override
public void insertFill(MetaObject metaObject) {
//属性名称,设置的值(当前时间),metaObject对象 ;当前时间 set createTime中去
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//mp执行修改时
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
多线程操作中或并发操作中,多人更改同一条数据,最后提交的事务,把之前的事务覆盖,丢失更新问题
修改实体类
在表添加字段作为版本号,在表对应实体类添加版本号属性
@Version
private Integer version;
创建配置文件 注册乐观锁插件
创建包config,创建文件MybatisPlusConfig.java
此时可以删除主类中的 @MapperScan 扫描注解
package com.mj.demomptest.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.mj.demomptest.mapper")
public class MpConfig {
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
通过多个id批量查询
//多个id批量查询
@Test
public void testSelect1(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
System.out.println(users);
}
简单的条件查询
@Test
public void testSelect2(){
Map<String,Object> columnMap = new HashMap<>();
columnMap.put("name","Jone");
columnMap.put("age",20);
List<User> users = userMapper.selectByMap(columnMap);
System.out.println(users);
}
配置分页查询插件
//分页查询插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
编写分页代码
插件Page对象,传入两个参数
当前页
每页显示数
调用mp的方法实现分页
//分页查询
@Test
public void testSelectPage(){
Page<User> page = new Page(1,3);
//new 的对象,条件
Page<User> userPage = userMapper.selectPage(page, null);
//返回对象得到分页所有数据
long pages = userPage.getPages();//总页数
long current = userPage.getCurrent();//当前页
List<User> records = userPage.getRecords();//查询数据集合
long total = userPage.getTotal();//总记录数
boolean hasNext = userPage.hasNext();//现在当前页是否有下一页
boolean hasPrevious = userPage.hasPrevious();//现在当前页是否有上一页
}
根据Id删除
//id删除
@Test
public void testDeleteId(){
int rows = userMapper.deleteById(1);
System.out.println(rows);
}
批量删除
@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
system.out.println(result);
}
简单条件删除
@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
int result = userMapper.deleteByMap(map);
system.out.println(result);
}
物理删除和逻辑删除
物理删除:表中数据不存在了
逻辑删除:表中数据还存在,但在查询时,查不出来
在表添加字段,作为逻辑删除标志,每次删除时,修改标志位
逻辑删除实现流程
数据库修改
添加delete字段 作为逻辑删除的标志
实体类修改
添加deleted 字段,并加上 @TableLogic 注解
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted; //逻辑删除标志
MyMetaObjectHandler.java
this.setFieldValByName("deleted",0,metaObject);
配置(可选)
0 - - -不删除
1 - - - 删除
测试
注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(1585882038232223746L);
System.out.println(result);
}
数据库中的数据并没有被删除,只是修改了 deleted的值 为1

测试逻辑后的删除查询


Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
ge 、gt、le、lt、isNull、isNotNull
@Test
public void testSel(){
//ge,gt,le,lt
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//表中的字段名字,值 age 大于等于21的
queryWrapper.ge("age",21);//大于等于
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}
eq(等于)、ne(不等于)
注意:seletOne()返回的是一条实体记录,当出现多条时会报错
//eq ne
@Test
public void testSelectOne(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name","Tom");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}

between、notBetween
包含大小边界
//between,notbetween
@Test
public void testSelectA(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//字段,开始值,结束值 age [22,28]
queryWrapper.between("age",22,28);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}

like、notlike、likeLeft、likeRight(%的右边)
update user set name like '%张'
selectMap()返回Map集合列表,通常配合select()使用
@Test
public void testSelectB(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//
queryWrapper.like("name","J");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}

orderBy、orderByDesc、orderByAsc 排序
@Test
public void testSelectC(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//
queryWrapper.orderByDesc("id");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}
| 查询方式 | 说明 |
|---|---|
| setSqlSelect | 设置 SELECT 查询字段 |
| where | WHERE 语句,拼接 + WHERE 条件 |
| and | AND 语句,拼接 + AND 字段=值 |
| andNew | AND 语句,拼接 + AND (字段=值) |
| or | OR 语句,拼接 + OR 字段=值 |
| orNew | OR 语句,拼接 + OR (字段=值) |
| eq | 等于= |
| allEq | 基于 map 内容等于= |
| ne | 不等于<> |
| gt | 大于> |
| ge | 大于等于>= |
| lt | 小于< |
| le | 小于等于<= |
| like | 模糊查询 LIKE |
| notLike | 模糊查询 NOT LIKE |
| in | IN 查询 |
| notIn | NOT IN 查询 |
| isNull | NULL 值查询 |
| isNotNull | IS NOT NULL |
| groupBy | 分组 GROUP BY |
| having | HAVING 关键词 |
| orderBy | 排序 ORDER BY |
| orderAsc | ASC 排序 ORDER BY |
| orderDesc | DESC 排序 ORDER BY |
| exists | EXISTS 条件语句 |
| notExists | NOT EXISTS 条件语句 |
| between | BETWEEN 条件语句 |
| notBetween | NOT BETWEEN 条件语句 |
| addFilter | 自由拼接 SQL |
| last | 拼接在最后,例如:last(“LIMIT 1”) |
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析: 在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1: print(k)k=k/2A.1000 B.10C.11D.9解析: 按照题意每次循环K/2,直到K值小于等
查看原文>>>基于”PLUS模型+“生态系统服务多情景模拟预测实践技术应用目录第一章、理论基础与软件讲解第二章、数据获取与制备第三章、土地利用格局模拟第四章、生态系统服务评估第五章、时空变化及驱动机制分析第六章、论文撰写技巧及案例分析基于ArcGISPro、Python、USLE、INVEST模型等多技术融合的生态系统服务构建生态安全格局基于生态系统服务(InVEST模型)的人类活动、重大工程生态成效评估、论文写作等具体应用基于ArcGISPro、R、INVEST等多技术融合下生态系统服务权衡与协同动态分析实践应用 本文从数据、方法、实践三方面对生态系统服务多情景预测进行讲解。内容涵盖多
据我了解.round()-ruby中的功能将小数向上舍入,最后一个有效数字是5?例如1.5.round(0)#=>2(OK)但为什么1.025.round(2)#=>1.02而不是我期望的1.03?irb(main):037:0>1.025.round(2)=>1.02我该怎么做才能解决这个问题? 最佳答案 这与最后一位数字为5无关,与将十进制值转换为double浮点值有关。http://en.wikipedia.org/wiki/Double_precision_floating-point_format基本上,十进制数必须以有限
1.下载安装概述:Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数据。使用Kibana,可以通过各种图表进行高级数据分析及展示。下载地址:Kibana8.1.0|Elastic解压到指定目录:tar-xzvfkibana-8.1.0-linux-x86_64.tar.gz-C/opt/module/2.Kibana生成证书文件在es服务器中生成证书、直接回车cd/opt/module/elasticsearch-8.1.0/bin/elasticsearch-certutilcsr-namekibana-dns
在Rails3(Ruby1.9.2)中我发送一个请求StartedGET"/controller/action?path=/41_+"但是参数列表是这样的:{"path"=>"/41_","controller"=>"controller","action"=>"action"}这里出了什么问题?-、*或.符号工作正常,只是+将被空格替换。 最佳答案 这是正常的URL编码,theplussignisashorthandforaspace:Withinthequerystring,theplussignisreservedasshor
文章目录一、Flex布局详解1.Flex布局的概念1.1传统布局1.2Flex布局1.3Flex布局声明2.Flex布局的容器属性2.1flex-direction属性2.2flex-wrap属性2.3flex-flow属性2.4justify-content属性2.5align-items属性2.6align-content属性3.Flex布局的项目属性3.1order属性3.2flex-grow属性3.3flex-shrink属性3.4flex-basis属性3.5flex属性3.6align-self属性总结一、Flex布局详解1.Flex布局的概念1.1传统布局盒子模型:我们知道当并列
最近更新的博客华为OD机试-数组合并(Python),真题含思路华为OD机试-最近的医院(Python),简单直白疑问搞懂,python中文词频统计,让你真能学会华为OD机试-最小传递延迟(Python)|代码编写思路+核心知识点字体反爬,一种来自字体设计师的跨行反爬案例|案例282023新华为OD机试题-事件推送(JavaScript)|刷完必过使用说明参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。华为OD清单查看地址:blog.csdn.net/hihell/category_12199275.html华为O
LVGL页面切换LVGL中没有明确的页面切换方案,参考(2.6#lvgl-多页面(screen)设定/切换)根据实际可用API,可以考虑两种方案:通过FLAG(LV_OBJ_FLAG_HIDDEN)隐藏或者显示lv_obj_add_flag/lv_obj_clear_flag根UI控件通过管理child节点的对象来实现lv_obj_set_parent/lv_obj_get_child通过屏幕显示obj切换lv_scr_load/lv_scr_load_anim与参考文章不同的是,这里更建议使用1和2两种方式进行管理。具体场景如下:如果是简单页面,没有标题,页脚,侧边栏等复杂元素,建议使用3。
文章目录02openEuler操作系统的安装2.1openEuler操作系统的安装流程2.2openEuler操作系统的安装详细步骤2.2.1下载地址2.2.2创建虚拟机2.2.2.1方法一:典型配置2.2.2.2方法二:自定义配置2.2.3安装过程02openEuler操作系统的安装2.1openEuler操作系统的安装流程2.2openEuler操作系统的安装详细步骤本次介绍openEuler22.03-LTS基于X86架构的安装。2.2.1下载地址官网下载地址:https://www.openeuler.org/zh/download/根据你的实际需求选择适合架构平台的ISO系统镜像下载