快速入门
官方文档快速入门案例
配置日志
# 配置日志mybatis-plus:configuration:# 配置 mybatis-plus执行的日志类型(可以看到执行过程) 下面是使用了控制台输出 sl4j log4j 等等都可以log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
效果
CRUD扩展
数据库中未指定id自增方式 我们可以通过mybatis-plus 来生成
插入一条数据
User user = new User();
user.setAge(3);
user.setName("xiuyuan");
user.setEmail("155645xxxx@qq.com");userMapper.insert(user);System.out.println(user);
你会发现,我们虽然没有指定id,但是他会自动给我们生成id,并赋给了user
数据库插入的id的默认值为:全局的唯一id
主键生成策略
分布式系统唯一Id生成方案汇总
Twitter的snowflake(雪花)算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。
mybatis-plus 默认主键生成方案 ID_WORKER
我们可以通过 @TableId 指定主键生成方式
public class User {@TableId(type = IdType.ID_WORKER)private Long id;private String name;private Integer age;private String email;
IdType
public enum IdType {AUTO(0), // 数据库id自增NONE(1), // 未设置主键INPUT(2), //手动输入ID_WORKER(3), // 默认的全局唯一idUUID(4), // 全局唯一id uuidID_WORKER_STR(5); // ID_WORKER 字符串表示法private int key;private IdType(int key) {this.key = key;}public int getKey() {return this.key;}
}
更新操作
@Testvoid update(){User user = new User();user.setId(2L);user.setAge(20);// 自动支持 动态sql(会自动判断 属性是否为''或null)int i = userMapper.updateById(user);}
从更新操作中 你会发现它是支持动态sql判断的(填充动态sql)。
自动填充
创建时间和修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
方式一 数据库级别(工作中不推荐)
方式二 代码级别
自动填充功能入门
1、实体类上添加填充注解
// 字段添加填充内容@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;
2、编写一个处理器来处理注解
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 {// 插入时填充的操作@Overridepublic void insertFill(MetaObject metaObject) {// 方法签名 MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)this.setFieldValByName("createTime",new Date(),metaObject);this.setFieldValByName("updateTime",new Date(),metaObject);}// 更新时填充的操作@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateTime",new Date(),metaObject);}
}
测试一下
乐观锁
mybaits-plus乐观锁官方文档
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
1、给数据库中增加version字段
2、我们的实体类同步字段
// mybatis-plus 的乐观锁 Version注解
@Version
private Integer version;
@Version 说明:
支持的数据类型只有:
int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下newVersion = oldVersion + 1
newVersion 会回写到 entity 中
仅支持 updateById(id) 与 update(entity, wrapper) 方法
在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
3、配置乐观锁插件(新版本已失效)
新版本已失效
@MapperScan("com.zlf.mapper")
@Configuration
public class mybatisPlusConfig {@Beanpublic OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){return new OptimisticLockerInnerInterceptor();}
}
新版本
@MapperScan("com.zlf.mapper")
@Configuration
public class mybatisPlusConfig {/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 配置 乐观锁拦截器OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);return interceptor;}@Beanpublic ConfigurationCustomizer configurationCustomizer() {return configuration -> configuration.setUseDeprecatedExecutor(false);}
}
测试
/*** 测试乐观锁失败(模拟多线程)*/@Testvoid testLock2(){// 1、查询用户信息User user = userMapper.selectById(1L);// 2、修改用户信息user.setEmail("cccc@abc");user.setAge(18);User user2 = userMapper.selectById(1L);user.setName("小白");// 插队修改userMapper.updateById(user2);userMapper.updateById(user);}
查询操作
基础查询
/*** 测试查询*/@Testvoid testSelect(){// 查询一个User user = userMapper.selectById(1L);// 查询多个 方法签名 List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);List<User> users = userMapper.selectBatchIds(Arrays.asList(1L,2L,3L));// 条件查询之一 selectByMapHashMap<String, Object> map = new HashMap<>();map.put("name","小白"); // key 是列名 value 是要查询的值map.put("age",18); // 多个条件之间是 andList<User> users1 = userMapper.selectByMap(map);}
分页查询
1、配置分页拦截器
/*** 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//分页拦截器interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 配置 乐观锁拦截器OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);return interceptor;}
2、直接使用Page对象
@Testvoid testPage(){// 参数一:当前页,参数二:显示条数Page<User> page = new Page<>(1,5);// 分页查询Page<User> userPage = userMapper.selectPage(page, null);// 获取记录 getRecords()userPage.getRecords().forEach(System.out::println);}
测试结果
删除操作
@Testvoid testDelete(){// 通过id删除一条记录userMapper.deleteById(1L);// 通过id集合删除整个集合对应记录userMapper.deleteBatchIds(Arrays.asList(2L,3L));// 通过条件删除 条件之间为 andMap<String, Object> map = new HashMap<>();map.put("name","小黑");map.put("age",18);userMapper.deleteByMap(map);}
逻辑删除
逻辑删除官方文档
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效!
类似管理员查看被删除的记录。防止数据的丢失,类似于回收站!
1、在数据表中添加一个字段deleted
2、在实体类中添加属性
@TableLogic //逻辑删除注解private Integer deleted;
3、配置
mybatis-plus:global-config:db-config:# 配置逻辑删除logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略@TableLogic)logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
测试
@Testvoid testDelete(){// 通过id删除一条记录userMapper.deleteById(2L);}
你会发现 删除变成了更新deleted 的值了
数据库中
我们再来查询一下
@Testvoid testLock(){// 1、查询用户信息User user = userMapper.selectById(2L);System.out.println(user);}
已经查不到了 sql中会过滤 deleted=0 的
性能分析插件
旧版本就不说了。
新版本在 执行 SQL 分析打印官方文档
条件构造器
条件构造器官方文档
代码自动生成器
这边使用的版本是3.4.1
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.4.1</version>
</dependency><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version>
</dependency>
代码生成器官方文档
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.util.ArrayList;@SpringBootTest
class MallApplicationTests {@Testvoid contextLoads() {}@Testpublic void run() {// 1、创建代码生成器AutoGenerator mpg = new AutoGenerator();// 2、全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("zlf");gc.setOpen(false); //生成后是否打开资源管理器gc.setFileOverride(false); //重新生成时文件是否覆盖gc.setServiceName("%sService"); //去掉Service接口的首字母Igc.setIdType(IdType.ID_WORKER); //主键策略gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型gc.setSwagger2(true);//开启Swagger2模式mpg.setGlobalConfig(gc);// 3、数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:3306/数据库名");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("xxxx");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);// 4、包配置PackageConfig pc = new PackageConfig();pc.setModuleName("mall"); //模块名pc.setParent("com");// com.zlf.edu.controllerpc.setController("controller");pc.setEntity("entity");pc.setService("service");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 5、策略配置StrategyConfig strategy = new StrategyConfig();strategy.setInclude("表名");strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作strategy.setRestControllerStyle(true); //restful api风格控制器strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符strategy.setLogicDeleteFieldName("is_deleted");// 自动填充配置TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);ArrayList<TableFill> tableFills = new ArrayList<>();tableFills.add(gmtCreate);tableFills.add(gmtModified);strategy.setTableFillList(tableFills);mpg.setStrategy(strategy);// 6、执行mpg.execute();}}
推荐B站Up狂神
良心up主,强烈推荐!!