MyBatisPlus
简介
mybatisi - plus是MyBatis的一个强大的增强工具包,用于简化开发。这个工具包为MyBatis提供了一些高效、有用、开箱即用的特性,使用它可以有效地节省您的开发时间。
可以简化CRUD代码
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作。BaseMapper
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,不用编写简单的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 操作智能分析阻断,也可自定义拦截规则,预防误操作
快速入门
导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>2.1.9</version>
</dependency>
实体类
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
Mapper
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
测试
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
配置日志
希望了解sql执行
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #使用默认的控制台输出
CRUD扩展
Insert
@Test
void test2() {
userMapper.insert(new User(7,"lyc",32,"2333@qq.com"));
contextLoads();
}
发现并没有问题
如果不插入id数字
@Test
void test2() {
User user = new User();
user.setAge(33);
user.setEmail("2333@33.com");
user.setName("lyc2");
userMapper.insert(user);
contextLoads();
}
}
mybatis-plus会自动插入一个id
update
void test3(){
User lyc = new User((long) 2, "lyc", 33, "2333@qq.com");
//通过条件自动拼接sql
//所有的sql都是动态配置
userMapper.updateById(lyc);
contextLoads();
}
自动填充(自动化更改)
创建时间,修改时间
gmt_create,gmt_modified
-
数据库级别
ALTER TABLE user ADD COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER email, ADD COLUMN `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER `create_time`;
更新的时候会自动更改update_time
-
代码级别插入
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
编写自动填充器
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start fill");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("update fill");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
逻辑删除
通过一个字段让它失效,delete=1
@TableLogic 字段注解
本质上执行update操作
查询的时候过滤掉delete字段等于1的字段
application.yaml
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
主键生成策略
uuid,自增id,雪花算法,redis生成
雪花算法
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增。
这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
- 第一个部分,是 1 个 bit:0,这个是无意义的。
- 第二个部分是 41 个 bit:表示的是时间戳。
- 第三个部分是 5 个 bit:表示的是机房 id,10001。
- 第四个部分是 5 个 bit:表示的是机器 id,1 1001。
- 第五个部分是 12 个 bit:表示的序号,就是某个机房某台机器上这一毫秒内同时生成的 id 的序号,0000 00000000。
SnowFlake算法的优点:
(1)高性能高可用:生成时不依赖于数据库,完全在内存中生成。
(2)容量大:每秒中能生成数百万的自增ID。
(3)ID自增:存入数据库中,索引效率高。
SnowFlake算法的缺点:
依赖与系统时间的一致性,如果系统时间被回调,或者改变,可能会造成id冲突或者重复。
数据库插入的id是数据库唯一的id
@TableId(type = IdType.AUTO)
private Long id;
乐观锁
定义
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁总是认为不会出现问题,无论干什么都不去上锁,如果出现了问题,再次更新值测试
悲观锁:无论干什么都会出现问题,无论干什么都会上锁再去操作
实现方式
-
取出记录时,获取当前version
-
更新时,带上这个version
-
执行更新时, set version = newVersion where version = oldVersion
-
如果version不对,就更新失败
-
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
update user set name="lyc", version = version +1 where id=2 and version =1;
--如果其他线程修改了 version版本发生改变,导致这个线程修改失败,保证了线程的安全
测试
void test3(){
User lyc=userMapper.selectById(5l);
lyc.setId((long) 5);
lyc.setName("xhc332");
if (userMapper.updateById(lyc)>0){
System.out.println("success");
}else {
System.out.println("failure");
};
}
分页查询
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
测试
@Test
void test4(){
//当前页 页面大小
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);
for (User record : page.getRecords()) {
System.out.println(record);
}
}
条件构造器
一些复杂的sql可以使用它可以替代
例:查询name不为空且邮箱不为空,且年龄大于等于12的用户
@Test
void test1(){
//查询name不为空且邮箱不为空,且年龄大于等于12的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}
实际拼接的sql语句
@Test
void test2(){
//名字等于lyc
userMapper.selectList(new QueryWrapper<User>().eq("name","lyc"));
}
具体的wrapper可以查看
https://baomidou.com/guide/wrapper.html#abstractwrapper
代码自动生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
模板引擎
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
public class LycCode {
public static void main(String[] args) {
//构建代码自动生成器对象
AutoGenerator mpg = new AutoGenerator();
//配置策略
//1. 全局配置
GlobalConfig gc = new GlobalConfig();
//获取当前项目目录
String projectPath = System.getProperty("user.dir");
//输出目录
gc.setOutputDir(projectPath+"/src/main/java");
//设置作者
gc.setAuthor("lyc");
//设置swagger2 实体属性注解
gc.setSwagger2(true);
//不打开资源管理器
gc.setOpen(false);
//不覆盖原来代码
gc.setFileOverride(false);
//去除service层前的i
gc.setServiceName("%sService");
//主键策略
gc.setIdType(IdType.ID_WORKER);
//设置日期类型
gc.setDateType(DateType.ONLY_DATE);
//代码构造器设置全局配置
mpg.setGlobalConfig(gc);
//2.数据源配置
DataSourceConfig dsc = new DataSourceConfig();
//设置密码
dsc.setPassword("123456");
//设置数据库类型
dsc.setDbType(DbType.MYSQL);
//设置连接数据库的url
dsc.setUrl("");
//设置驱动的名字
dsc.setDriverName("com.mysql.jdbc.Driver");
//设置用户名
dsc.setUsername("lyc");
//代码构造器设置数据源配置
mpg.setDataSource(dsc);
//3.包配置
PackageConfig pc = new PackageConfig();
//
pc.setModuleName("blog");
pc.setParent("com.lyc");
mpg.setPackageInfo(pc);
//4.策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
//是否启用lombok插件
strategy.setEntityLombokModel(true);
//驼峰命名
strategy.setRestControllerStyle(true);
//逻辑删除字段
strategy.setLogicDeleteFieldName();
// 公共父类
strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));//设置映射的表
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
//自动填充字段
TableFill tableFill = new TableFill("gmt_create", FieldFill.INSERT);
strategy.setTableFillList();
mpg.setStrategy(strategy);
//执行代码构造
mpg.execute();
}
}