文章目录
1.概述
MybatisPlus是对Mybatis的基础上进行了增强,不会对原有的工程产生影响,简单的配置实现CRUD
2.流程
-
导入MybatisPlus 和 mysql的坐标
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
-
创建实体类
-
创建mapper
-
mapper扫描
-
测试中使用MybatisPlus的自带方法进行测试
3.常用设置
3.1 配置实体类名映射的数据库表名
-
在实体类上添加@TableName(“数据库表名”)的方式
-
配置全局前缀
mybatis-plus: global-config: db-config: #表名前缀 table-prefix: tb_ #设置主键按照数据库设置自增长 # id-type: auto configuration: #设置关闭驼峰 map-underscore-to-camel-case: false
3.2 配置主键自增
-
在实体类的主键上添加@TableId(type = IdType.AUTO)
-
配置全局
mybatis-plus: global-config: db-config: #表名前缀 table-prefix: tb_ #设置主键按照数据库设置自增长 # id-type: auto configuration: #设置关闭驼峰 map-underscore-to-camel-case: false
3.3 字段和列名的驼峰映射
默认情况下MP会自动开启驼峰命名映射,如果需要关闭使用以下配置
mybatis-plus:
global-config:
db-config:
#表名前缀
table-prefix: tb_
#设置主键按照数据库设置自增长
# id-type: auto
configuration:
#设置关闭驼峰
map-underscore-to-camel-case: false
3.4 设置字段映射关系
默认情况下MP会根据实体类的字段名去映射数据库表的列名
如果数据库的列名和实体类的字段名不一致,我们可以使用@TableField注解的value设置去配置映射关系
@TableField("username")
private String userName
3.5 日志
mybatis-plus:
global-config:
db-config:
#表名前缀
table-prefix: tb_
#设置主键按照数据库设置自增长
# id-type: auto
configuration:
#日志打印在控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4.基本使用
4.1 插入
使用insert方法来实现数据的插入
示例:
User user = new User();
user.setUserName("灰二");
user.setPassword("1234");
int row = userMapper.insert(user);
System.out.println(row);
4.2 删除
根据id集合删除
示例:
List<Integer> ids = new ArrayList<>();
ids.add(5);
ids.add(6);
int rows = userMapper.deleteBatchIds(ids);
System.out.println(rows);
根据单个id删除
示例:
int row = userMapper.deleteById(8);
System.out.println(row);
根据条件集合删除
示例:
Map<String,Object> columnMap = new HashMap();
columnMap.put("user_name", "灰二");
int rows = userMapper.deleteByMap(columnMap);
System.out.println(rows);
4.3 更新
根据id更改信息
示例:
User user = new User();
user.setId(7L);
user.setUserName("灰二");
int row = userMapper.updateById(user);
System.out.println(row);
4.4 查询
查询所有
示例:
List<User> users = userMapper.selectList(null);
System.out.println(users);
5.Wrapper条件构造器
5.1 概述
5.2 常用AbstractWrapper方法
eq : equals等于
gt : greater than 大于
ge : greater than or equals 大于等于
lt : less than 小于
le : less than or equals 小于等于
between : 相当于SQL中的BETWEEN
like : 模糊匹配 %
likeRight : 模糊匹配右边
likeLeft : 模糊匹配左边
notLike : not like …
isNull
isNotNull
and
or
in
groupBy
orderByAsc : 升序
orderByDesc : 降序
示例一:
select *
from tb_user
where age > 18 and address = '上海'
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.gt("age",18);
wrapper.eq("address","上海");
List<User> userList = userMapper.selectList(wrapper);
示例二:
select *
from tb_user
where id in(1,2,3) and age BETWEEN 12 and 29 and address like '%上%'
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.in("id",1,2,3);
wrapper.between("age",12,29);
wrapper.like("address","%上%");
List<User> userList = userMapper.selectList(wrapper);
示例三:
select *
from tb_user
where id in(1,2,3) and age > 10
order by age Desc
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.in("id",1,2,3);
wrapper.gt("age",10);
wrapper.orderByDesc("age");
List<User> userList = userMapper.selectList(wrapper);
5.3 常用QueryWrapper方法
QueryWrapper的select可以设置要查询的列
示例一
查询部分列
select id,user_name from tb_user
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.select("id","user_name");
List<User> users = userMapper.selectList(queryWrapper);
示例二
select (class entityClass,Predicate predicate)
方法的第一个参数为实体类的字节码对象,第二个参数为Predicate类型,可以使用lambda的写法,过滤要查询字段(主键除外,因为主键会查)
select id,user_name from tb_user
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.select(User.class,new Predicate<TableFieldInfo>(){
@Override
public boolean test(TableFieldInfo tableFieldInfo){
return "user_name".equals(tableFieldInfo.getColumn);
}
});
List<User> users = userMapper.selectList(queryWrapper);
示例三
selectPredicate predicate)
select
id,user_name,password,name,age
from
tb_user
QueryWrapper<User> queryWrapper = new QueryWrapper(new User());
queryWrapper.select(new Predicate<TableFieldInfo>(){
@Override
public boolean test(TableFieldInfo tableFieldInfo){
return !"address".equals(tableFieldInfo.getColumn);
}
});
List<User> users = userMapper.selectList(queryWrapper);
QueryWrapper<User> queryWrapper = new QueryWrapper(new User());
queryWrapper.select(tableFieldInfo -> !"address".equals(tableFieldInfo.getColumn()));
List<User> users = userMapper.selectList(queryWrapper);
5.4 常用updateWrapper方法
示例:
update tb_user set age = 99 where id > 1
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
userUpdateWrapper.set("age", 99);
userUpdateWrapper.gt("id",1);
int rows = userMapper.update(null, userUpdateWrapper);
System.out.println(rows);
5.5 Lambda条件构造器
示例:
select id,userIname,password,name,age,address
from tb_user
where age > 18 and address = '上海'
未使用Lambda条件构造器实现:
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.gt("age", 18);
userQueryWrapper.eq("address", "上海");
List<User> users = userMapper.selectList(userQueryWrapper);
System.out.println(users);
使用Lambda条件构造器实现:
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.gt(User::getAge, 18);
queryWrapper.eq(User::getAddress, "上海");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
6.自定义SQL语句
6.1 Mybatis方式
① 定义方法
@Repository
public interface UserMapper extends BaseMapper<User> {
User findMyUser(Long id);
}
② 创建XML
指定xml的存放位置:
mapper-locations: classpath*:/mapper/**/*.xml
创建mapper目录
创建相应的XML文件
③ 在XML中编写相应的SQL语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.huier.mapper.UserMapper">
<select id="findMyUser" resultType="User">
select * from tb_user where id = #{id}
</select>
</mapper>
④ 调用测试
User myUser = userMapper.findMyUser(7L);
System.out.println(myUser);
6.2 Mybatis方式结合条件构造器
① 方法定义中添加Wrapper类型的参数
添加Wrapper类型的参数,并且要注意给其指定参数名
User findMyUserByWrapper(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
② 在SQL语句中获取Wrapper拼接的SQL片段进行拼接
<!--${}参与预编译-->
<select id="findMyUserByWrapper" resultType="User">
select * from tb_user ${ew.customSqlSegment}
</select>
③ 测试
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", 7,9);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
7.分页查询
7.1 基本分页查询
① 配置分页查询拦截器
@Configuration
public class PageConfig {
/**
* @Author HuiEr
* @Date 2022/9/24 20:08
* @Version 2020
* @Description 配置分页拦截器 3.4.0之后版本实现方法
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}进行分页查询
② 进行分页查询
//page 和 userIPage是同一个对象
IPage<User> page = new Page<>();
//设置分页相关信息
page.setCurrent(1);
page.setSize(1);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", 7,9);
IPage<User> userIPage = userMapper.selectPage(page, queryWrapper);
System.out.println(userIPage.getRecords());//当前页的数据
System.out.println(userIPage.getTotal());//总记录数
7.2 多表分页查询
如果需要在多表查询时进行分页查询的话,就可以在mapper接口中自定义方法,然后让方法接收Page对象
示例
需求
我们需求去查询Orders表,并且要求查询的时候除了要获取到Orders表中的字段,还要获取到每个订单的下单用户的用户名。
准备工作
SQL准备
SELECT
o.*,u.`user_name`
FROM
tb_user u,
tb_orders o
WHERE o.`user_id` = u.`id`
实体类修改
增加一个userName属性
@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName(value = "tb_orders")
public class Orders implements Serializable{
@TableId(type = IdType.AUTO)
private Long id;
//价格
private Integer price;
//备注
private String remark;
//用户id
private Integer userId;
//更新时间
private Date updateTime;
//创建时间
private Date createTime;
//版本
private Integer version;
//逻辑删除表示,0-未删除,1-删除
private Integer delFlag;
//创建人
private String createBy;
//更新人
private String updateBy;
private String userName;
}
实现
第一个参数为Ipage类型
IPage<Orders> findAllOrders(IPage<Orders> page);
在xml中不需要关心分页操作,MP会帮助我们完成>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.huier.mapper.OrdersMapper">
<select id="findAllOrders" resultType="Orders">
SELECT
o.*,u.`user_name`
FROM
tb_user u,
tb_orders o
WHERE o.`user_id` = u.`id`
</select>
</mapper>
IPage<Orders> page = new Page<>();
page.setCurrent(1);
page.setSize(3);
IPage<Orders> allOrders = ordersMapper.findAllOrders(page);
System.out.println(allOrders.getRecords());
System.out.println(allOrders.getTotal());
8.Service层接口
MP也为我们提供了Service层的实现,我们只需要编写一个接口,继承IService,并创建一个接口实现类继承ServiceImpl,即可使用
相较于Mapper接口,Service层主要是支持了更多批量操作的方法
8.1 基本使用
接口
public interface UserService extends IService<User> {
}
实现类
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
}
测试
List<User> list = userService.list();
System.out.println(list);
8.2 自定义方法
9.代码生成器
MP提供了一个代码生成器,可以让我们一键生成实体类、Mapper接口、Service、Controller等全套代码,使用如下
①添加依赖
<!--mybatisPlus代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--模板引擎-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
②生成
修改相应的配置即可
public class GeneratorTest {
@Test
public void generator(){
AutoGenerator generator = new AutoGenerator();
//全局配置
GlobalConfig config = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
//设置输出到的目录
config.setOutputDir(projectPath + "/src/main/java");
config.setAuthor("huier");
//生成结束后是否打开文件夹
config.setOpen(false);
//全局配置添加到 generator 上
generator.setGlobalConfig(config);
//数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mysql://127.0.0.1:3306/mp_db?serverTimezone=Asia/Shanghai");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("root");
//数据源配置添加到 generator
generator.setDataSource(dataSourceConfig);
//包配置 生成的代码放在哪个包下
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.huier.mp.generator");
//包配置添加到 generator
generator.setPackageInfo(packageConfig);
//策略配置
StrategyConfig strategyConfig = new StrategyConfig();
//下划线驼峰转换
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
//开启lombok
strategyConfig.setEntityLombokModel(true);
//开启RestController
strategyConfig.setRestControllerStyle(true);
generator.setStrategy(strategyConfig);
generator.setTemplateEngine(new FreemarkerTemplateEngine());
//开始生成
generator.execute();
}
}
10.自动填充
示例
①在对应字段上增加注解
使用@TableField注解的fill属性来标注哪些字段需要自动填充,加了注解MP才会在对应的SQL中为我们预留字段,而属性值代表我们在干什么进行什么操作时需要预留字段
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
//创建时间
@TableField(fill = FieldFill.INSERT)
private Date createTime;
②自定义填充处理器 MetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//插入操作时 需要自动更新
this.setFieldValByName("createTime",new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
//修改操作时 需要自动更新
this.setFieldValByName("updateTime", new.Date(), metaObject);
}
}
11.逻辑删除
如果3.3.0版本之前还需要在对应的字段上加上@TableLogic注解
mybatis-plus:
global-config:
db-config:
#表名前缀
table-prefix: tb_
logic-delete-field: delFlag #全局逻辑删除的实体字段名
logic-delete-value: 1 #逻辑已删除(默认为1)
logic-not-delete-value: 0 #逻辑未删除(默认为0)
#设置主键按照数据库设置自增长
id-type: auto
configuration:
#日志打印在控制台
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置关闭驼峰
map-underscore-to-camel-case: true
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.huier.domain.entity
12.乐观锁
并发操作时,我们需要保证对数据的操作不发生冲突。乐观锁就是其中一种方式。乐观锁就是先加上不存在并发冲突问题,在进行实际数据操作时再检查是否冲突
我们在使用乐观锁时一般在表中增加一个version列。用来记录我们每天记录操作的版本。每次对某记录进行操作时,对应的版本需要+1
然后我们在每次进行更新操作时,先查询对应数据的version值。在执行更新时,set version=老版本+1 where version = 老版本
如果在查询老版本号到更新操作的中间时刻有其他人更新了这条数据,这样这次更新语句就会更新失败。
MP提供了乐观锁插件
使用后方便对verison的操作
12.1 使用
①配置对应插件
@Configuration
public class MybatisPlusConfig {
/**
* 旧版
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
②在实体类的字段上加上@Version注解
//版本
@Version
private Integer version;
③更新
注意 : 在更新前我们一定要先查询到version设置到实体类上再进行更新才能生效
//查询id为3的数据
Orders orders = ordersMapper.selectById(3L);
//对id为3的数据进行更新 把price修改为8888
orders.setPrice(8888);
ordersMapper.updateById(orders);
13.多插件配置问题
3.4.0之后的版本,如果需要用到多个插件的话要注意。在配置的时候只需要注入一个MybatisPlusInterceptor对象
顺序:
- 分页
- 乐观锁
例如:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//分页
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}