快速入门
MybatisPlus是基于Mybatis框架基础上开发的增强型工具,旨在简化开发,提高效率
官方地址:http://mp.baomidou.com/
开发方式
- 基于Mybatis使用MybatisPlus
- 基于Spring使用MybatisPlus
- 基于SpringBoot使用MybatisPlus
我们这里采用SpringBoot使用MybatisPlus进行开发:
- 首先添加依赖
添加MybatisPlus依赖(需要手动添加)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
配置yml文件:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.util.DriverDataSource
url: jdbc:mysql://localhost:3306/mybatistest
username: root
password:
进行入门开发:
public interface UserDao extends BaseMapper<User>{
}
与之前的mybatis对比,在该类中,不用进行相应的sql语句的编写,只需要继承一个BaseMapper,再在泛型中填入实体类,就会自动生成一系列的方法
MybatisPlus特性
这里是其主要的几个新特性,具体的请到官网进行学习
- 无侵入:只做增强不做改变,不会对现有工程产生影响
- 强大的CRUD操作:内置通用Mapper,少量配置即可实现单表CRUD操作
- 支持Lambda:编写查询条件无需担心字段写错
- 支持主键自动生成
- 内置分页插件
标准数据层开发
直接使用对应功能的方法即可完成对应的操作
分页查询
调用selectPage()
方法进行分页查询,其中有参数Ipage类型的参数说明第几页,没有多少条记录
@Test
void testselectpage(){
Ipage page=new page(1,2); //1表示第1页,2表示一页有2条信息
userDao.selectPage(page,null); //第一个参数是Ipage对象,第二个是关于查询的
//page对象中还有很多关于分页的信息
System.out.println("当前页码值:"+page.getCurrent());
System.out.println("每页显示数:"+page.getSize());
System.out.println("一共多少页:"+page.getPages());
System.out.println("一共多少条数据:"+page.getTotal());
System.out.println("数据:"+page.getRecords());
}
注意:这里查询出来的数据依然在page对象当中
运行后发现部分数据没有显示出来,原因是没有配置mybatisplus的分页拦截器,只有配置后才会进行分页
需要新建配置类进行配置:
@Configuration
public class mybatisplusconfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//定义MP的拦截器
MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
开启mybatisplus控制台配置(yml):
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
按条件查询
按照条件进行查询使用示例:
查询小于某数据的信息:
//方式一:按条件进行查询
QueryWapper qw=new QueryWapper();
qw.lt("age",18); //方法参数中填写查询条件参数
List<User> userList=userDao.selectList(qw);
System.out.println(userList);
//方式二:Lambda格式条件查询
QueryWapper<User> qw=new QueryWapper<User>();
qw.lambda().lt(User::getAge,18); //方法参数中填写查询条件参数
List<User> userList=userDao.selectList(qw);
System.out.println(userList);
//方式三: 简化的Lambda格式条件查询
LambdaQueryWapper<User> qw=new LambdaQueryWapper<User>();
qw.lt(User::getAge,18); //方法参数中填写查询条件参数
List<User> userList=userDao.selectList(qw);
System.out.println(userList);
方式一由于其中的参数可能会写错导致出现问题,所以采用方式二的写法,在方式二中必须加上泛型,为了简化方式二的书写,采用方式三进行开发
多条件如何开发:
LambdaQueryWapper<User> qw=new LambdaQueryWapper<User>();
qw.lt(User::getAge,18); //方法参数中填写查询条件参数
qw.gt(User::getAge,15); //查询大于15的数据
List<User> userList=userDao.selectList(qw);
System.out.println(userList);
//或者将上述改造成条件编程
qw.lt(User::getAge,18).gt(User::getAge,15);//而且这是并且的关系
qw.lt(User::getAge,18).or().gt(User::getAge,15);//这是或者的关系
如果出现需要动态SQL的问题该怎么处理:
qw.lt(null!=数据..,User::getAge,数据);
这样写表示数据不为空的时候才使用这个条件语句
查询投影
简单就是说控制数据以什么方式展现出来
LambdaQueryWapper<User> qw=new LambdaQueryWapper<User>();
qw.select(User::getId,User::getName,User::getAge);//表示只显示这三个字段
List<User> userList=userDao.selectList(qw);
还可以查询聚合函数的结果:
QueryWapper<User> qw=new QueryWapper<User>();
qw.select("count(*) as count");
qw.groupBy("tel");//进行分组查询
List<Map<String,Object>> userList=userDao.selectMaps(qw);
System.out.println(userList);
//这样就是以键值对的形式返回数据
- 等匹配查询(相当于=查询)
qw.eq(User::getName,"nihao").eq(User::getPassword,"123456");
User user=userDao.selectOne(qw);
- 范围查询
qw.between(User::getAge,10,20);// 第二个参数为小,第三个参数为大
- 模糊匹配
qw.like(User::getName,"J");
DQL编程控制
出现数据库表中的字段名称与实体类中的名称不一样,实体类中的属性多余数据库表的字段,表名与类名不同
这种情况可以使用 @TableField注解来解决
位置:模型类属性定义上方
作用:设置当前属性对应的数据库表中的字段关系
相关属性:
value:设置数据库表字段的名称
exist:设置属性在数据库表字段中是否存在,默认为true,此属性无法与value合并使用
select:设置属性是否参与查询,此属性与select()映射配置不冲突
public class User{
@Tablefield(exist=false)
private Integer online;
@Tablefield(value="pwd")
private String password;
}
表名与类名不同可以使用 @TableName(“表名”) 来进行注解
DML编程控制
通过注解 @TableId
位置:模型类中用于表示主键的属性定义上方
作用:设置当前类中主键属性的生成策略
相关属性:
value:设置数据库主键名称
type:设置主键属性的生成策略,值参照IdType枚举值
public class User{
@TableId(type=IdType.AUTO)
private Long id;
}
- id生成策略
雪花算法生成id:
占位符默认为0,时间戳是系统自定义的时间戳计算法,机器码代表是在哪台机器上,序列号是当前时间共同产生的算法指令其中是第几个
@TableName以及 @TableId也可以通过全局进行配置
# 通过配置选择雪花算法
global-config:
db-config:
id-type: assign_id
# 配置数据库表名称
table-prefix:
- 按照多个id进行删除
List<Long> list=new ArrayList<>();
list.add(....);
list.add(....);
userDao.deleteBatchIds(list);
- 按照多个id查询数据
List<long> list=new ArrayList<>();
list.add(...);
list.add(...);
userDao.selectBatchIds(list);
逻辑删除
为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
在数据库表中添加字段进行判定
在对应的实体类中添加对应的属性,并通过注解 @TableLogic进行设定
//在实体类中
//逻辑删除字段,标记当前记录是否被删除
@TableLogic(value="0",delval="1") //value表示默认值
private Integer deleted;
同样这个逻辑删除的注解也能够通过配置解决:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
注意:当使用逻辑删除时,对应的删除语句就会在底层转变为更新语句,更新逻辑字段值达到逻辑删除的目的
乐观锁
解决小项目开发防止并发问题的解决方法
方法:(添加新字段version)
在数据库表中添加一个字段,用来表示当前是谁在操作数据,假定当前用户version值时1,数据库version值也是1,这是该用户就能够操作字段,操作完之后是这个用户的version值加一这个样这个用户就访问不了数据库表,这样就交由后面的人来访问
如何实现访问后用户的version值加一,通过拦截器进行这个语句的实现
//添加乐观锁拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
在实体类中通过注解说明字段:
@Version
private Integer version;
代码生成器
如果在开发中遇到需要很多重复的代码时,但只是其中一些字段不一样,就可以使用代码生成器,例如:
针对这一现象,mybatisPlus提供代码生成器
模板:MybatisPlus提供大量模板
数据库相关配置:读取数据库获取信息
开发者自定义配置:手工配置
首先需要配置代码生成器以及模板引擎依赖
<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>
创建好之后如何使用代码生成器
- 创建一个代码生成器对象
- 方法创建模板代码
假如说要自动根据数据库生成一个模板:
public class shengTest {
public static void main(String[] args) {
AutoGenerator autoGenerator=new AutoGenerator();
//设置数据源
DataSourceConfig dataSource=new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatistest");
dataSource.setUsername("root");
dataSource.setPassword("");
autoGenerator.setDataSource(dataSource);
autoGenerator.execute();
}
}
运行后会给出一个文件弹窗,根据路径选择对应的数据库代码模板
但是这时候就浮现出了很多问题,比如说生成的代码放在什么位置等等,这个时候就需要对代码生成器进行全局配置
设置生成器的全局配置 :
//设置生成器全局配置
GlobalConfig globalConfig=new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatisplustest/src/main/java"); //设置代码模板生成的位置,user.dir表示用户的本地目录
globalConfig.setOpen(false); //设置生成完毕后是否打开代码生成所在目录
globalConfig.setAuthor("nihao"); //生成作者
globalConfig.setFileOverride(true); //设置是否覆盖原始生成的文件
globalConfig.setMapperName("%sDao"); //设置数据层接口名,%s为占位符,指模块名称
globalConfig.setIdType(IdType.ASSIGN_ID); //设置Id生成策略
autoGenerator.setGlobalConfig(globalConfig);
设置包名相关配置:
//设置包名相关配置
PackageConfig packageConfig=new PackageConfig();
packageConfig.setParent("com.nihao");//设置生成包名,与代码所在位置不冲突,二者叠加组成完整路径
packageConfig.setEntity("pojo"); //设置实体类包名
packageConfig.setMapper("Mapper"); //设置数据层包名
autoGenerator.setPackageInfo(packageConfig);
设置策略设置:
//策略设置
StrategyConfig strategyConfig=new StrategyConfig();
strategyConfig.setInclude("tbl_User"); //设置当前参与生成的表名,参数为可变参数
strategyConfig.setTablePrefix("tbl_"); //设置数据库表的前缀名称 模块名=数据库表名称-前缀名称
strategyConfig.setRestControllerStyle(true); //设置是否启用REST风格
strategyConfig.setVersionFieldName("version"); //设置乐观锁字段名
strategyConfig.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名
strategyConfig.setEntityLombokModel(true); //设置是否启用lombok