一.为什么要使用mybatis-plus
1. 简化开发
- 减少样板代码:MyBatis-Plus 封装了大量的 CRUD 操作,开发者无需为每个实体类编写复杂的 Mapper 文件和 SQL 语句,从而减少了大量的样板代码。
- 自动填充:支持插入和更新时的字段自动填充,比如创建时间和更新时间,可以自动设置,减少手动赋值的工作量。
2. 功能丰富
- 内置分页插件:提供了一套简单易用的分页插件,支持多种数据库的分页查询,开发者只需几行代码即可实现分页功能。
- 条件构造器:提供了强大的条件构造器,可以轻松地构建复杂的查询条件,包括但不限于模糊查询、范围查询、排序等。
- 乐观锁:内置了乐观锁机制,帮助解决高并发环境下的数据竞争问题。
- 性能分析插件:可以监控 SQL 执行情况,帮助开发者发现并优化慢查询。
3. 无缝集成
- 兼容 MyBatis:作为 MyBatis 的增强工具,MyBatis-Plus 完全兼容 MyBatis 的所有特性,同时提供更多的增强功能。这意味着开发者可以在现有 MyBatis 项目中无缝引入 MyBatis-Plus,而不需要对原有代码进行大规模修改。
- Spring Boot 集成:与 Spring Boot 的集成非常方便,通过几个简单的配置就可以快速上手使用。
4. 社区活跃
- 活跃的社区支持:MyBatis-Plus 拥有一个活跃的开发者社区,官方文档详尽,遇到问题时可以很容易地找到解决方案或得到帮助。
5. 开源免费
- 开源免费:作为一个开源项目,MyBatis-Plus 免费提供给个人和企业使用,没有商业限制,适合各种规模的应用开发。
6. 提高开发效率
- 提高开发效率:通过减少重复劳动,简化开发流程,使得开发者可以更加专注于业务逻辑的实现,从而大大提高了开发效率。
综上所述,MyBatis-Plus 不仅继承了 MyBatis 的优点,还在此基础上增加了许多实用的功能,极大地提升了开发效率和代码质量。如果你正在寻找一种既能简化数据库操作又能提高项目开发速度的方法,MyBatis-Plus 是一个值得尝试的选择。
二.spring-boot集成mybatis-plus
1.引入依赖
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
注: (mybatis-plus是mybatis的增强版,它只做增强不做修改,mybatis-plus中拥有mybatis的依赖,不需要再引入mybatis的相关依赖,否则可能会出现版本冲突问题)
2.添加配置
bootstrap.yml格式:
mybatis-plus:
type-aliases-package: com.story.domain # 别名扫描包,指定实体类所在的包路径(改成自己的实体类路径)
# 以下配置都是默认值,可以根据项目情况进行修改
mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml 文件地址
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 语句
map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射
cache-enabled: false # 是否开启二级缓存
global-config:
db-config:
id-type: assign_id # 默认雪花算法,另外还有 auto(自增id) assign_uuid(uuid)
update-strategy: not_null # 更新策略: 只更新非空字段
application.properties格式:
# MyBatis-Plus 配置
# 别名扫描包,指定实体类所在的包路径(改成自己的实体类路径)
mybatis-plus.type-aliases-package=com.story.domain
# Mapper.xml 文件地址,指定映射文件的位置
mybatis-plus.mapper-locations=classpath*:/mapper/**/*.xml
# MyBatis 配置
# 设置 MyBatis 的日志实现,这里使用标准输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 是否开启下划线和驼峰的映射,例如将数据库中的 user_name 映射为实体类中的 userName
mybatis-plus.configuration.map-underscore-to-camel-case=true
# 是否开启二级缓存,默认为 false
mybatis-plus.configuration.cache-enabled=false
# MyBatis-Plus 全局配置
# 主键生成策略,默认使用雪花算法(assign_id),还可以选择 auto(自增)、assign_uuid(UUID)
mybatis-plus.global-config.db-config.id-type=assign_id
# 更新策略,设置为 not_null 表示只更新非空字段
mybatis-plus.global-config.db-config.update-strategy=not_null
3.实体类
/**
* 用户实体类
*/
@Data
public class User {
/**
* 主键 ID,使用雪花算法生成
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 用户名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
/**
* 部门id
*/
private Integer departmentId;
}
注解解释:
1.@TableId: 用于标识实体类中的主键字段
属性:
- type: 主键生成策略,可选值包括:
- IdType.AUTO: 数据库自增
- IdType.INPUT: 外部输入
- IdType.NONE: 无主键
- IdType.ASSIGN_ID: 使用雪花算法生成主键
- IdType.ASSIGN_UUID: 使用 UUID 生成主键
- IdType.ID_WORKER: 使用 Twitter 的 Snowflake 算法生成主键
- IdType.UUID: 使用 UUID 生成主键
@TableId(type = IdType.AUTO)
private Long id;
2.@TableName: 用于指定实体类对应的数据库表名
属性:
value:表名
@TableName("user")
public class User {
// 字段
}
3.@TableField:用于标识实体类中的普通字段
属性:
value: 字段名
exist: 是否存在该字段(默认为 true),如果设置为 false,则在生成 SQL 时不会包含该字段
fill: 字段填充策略,可选值包括:
FieldFill.DEFAULT: 默认不填充
FieldFill.INSERT: 插入时填充
FieldFill.UPDATE: 更新时填充
FieldFill.INSERT_UPDATE: 插入和更新时都填充
@TableField("user_name")
private String name;
4.@TableField(fill = FieldFill.INSERT): 用于自动填充字段
属性:
fill: 字段填充策略,可选值包括:
FieldFill.DEFAULT: 默认不填充
FieldFill.INSERT: 插入时填充
FieldFill.UPDATE: 更新时填充
FieldFill.INSERT_UPDATE: 插入和更新时都填充
/**
* 用户实体类
*/
@Data
@TableName("user") // 指定表名
public class User {
/**
* 主键 ID,使用雪花算法生成
*/
@TableId(type = IdType.ASSIGN_ID) // 主键生成策略
private Long id;
/**
* 用户名
*/
@TableField("user_name") // 指定字段名
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
/**
* 创建时间,插入时自动填充
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新时间,更新时自动填充
*/
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 逻辑删除字段
*/
@TableLogic
private Integer deleted;
/**
* 版本号,用于乐观锁
*/
@Version
private Integer version;
/**
* 临时字段,不在数据库表中
*/
@TableField(exist = false)
private String tempField;
}
4.数据访问层(mapper层)
创建mapper接口继承BaseMapper
/**
* 用户 Mapper 接口
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 可以在这里添加自定义的 SQL 方法
}
5.业务逻辑层(service层)
创建Service 接口继承IService
/**
* 用户服务接口
*/
public interface UserService extends IService<User> {
// 可以在这里添加自定义的服务方法
}
创建接口的实现类 继承ServiceImpl并实现service接口
/**
* 用户服务实现类
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 可以在这里添加自定义的服务方法实现
}
6.表现层(controller层)
/**
* 用户控制器
*/
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 获取所有用户
* @return 用户列表
*/
@GetMapping
public List<User> getAllUsers() {
return userService.list();
}
/**
* 根据 ID 获取用户
* @param id 用户 ID
* @return 用户对象
*/
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
/**
* 添加用户
* @param user 用户对象
* @return 添加的用户对象
*/
@PostMapping
public User addUser(@RequestBody User user) {
userService.save(user);
return user;
}
/**
* 更新用户
* @param id 用户 ID
* @param user 用户对象
* @return 更新后的用户对象
*/
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
userService.updateById(user);
return user;
}
/**
* 删除用户
* @param id 用户 ID
*/
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.removeById(id);
}
}
7.数据库建表
CREATE TABLE user (
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(255),
age INT,
email VARCHAR(255),
department_id INT
);
CREATE TABLE department (
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(255)
)
三.mybatis-plus实现多表联合查询
1.添加依赖
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.11</version>
</dependency>
2.创建/修改mapper接口,继承MPJBaseMapper 如下:
/**
* 用户 Mapper 接口
*/
@Mapper
public interface UserMapper extends MPJBaseMapper<User> {
// 可以在这里添加自定义的 SQL 方法
}
3.创建部门实体类
@Data
@TableName("department")
public class Department {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 部门名称
*/
private String name;
}
4.创建部门mapper接口
@Mapper
public interface DepartmentMapper extends MPJBaseMapper<Department> {
}
5.创建响应对象实体类
@Data
public class UserResponse {
/**
* 主键 ID,使用雪花算法生成
*/
private Long id;
/**
* 用户名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
/**
* 部门id
*/
private Integer departmentId;
/**
* 部门名称
*/
private String departmentName;
}
6.controller层添加以下方法
/**
* 获取所有用户
* @return 用户列表
*/
@GetMapping("getList")
public List<UserResponse> getUserList() {
return userService.getList();
}
7.service接口及实现类实现上述方法
service接口:
/**
* 用户服务接口
*/
public interface UserService extends IService<User> {
/**
* 查询用户信息
* @return 用户列表
*/
List<UserResponse> getList();
}
service实现类:
/**
* 用户服务实现类
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<UserResponse> getList() {
//这里的泛型是主表的类型
MPJLambdaWrapper<User> wrapper = new MPJLambdaWrapper<>();
// 选择 User 表的所有字段
wrapper.selectAll(User.class)
// 选择 Department 表的 name 字段,并将其映射到 UserResponse 的 departmentName 字段
.selectAs(Department::getName, UserResponse::getDepartmentName)
// 左连接 Department 表
.leftJoin(Department.class, Department::getId, User::getDepartmentId);
// 执行查询并返回结果列表
List<UserResponse> result = userMapper.selectJoinList(UserResponse.class, wrapper);
return result;
}
}
MPJLambdaWrapper 是 mybatis-plus-join 插件提供的一个条件构造器,类似于 MyBatis-Plus 的 LambdaQueryWrapper,但支持多表联查。下面是MPJLambdaWrapper 的常用方法及其用法
1. 选择字段
- select(Class clazz, SFunction... columns): - 选择指定表中的字段。- 示例:wrapper.select(User.class, User::getId, User::getName)
- selectAll(Class clazz): - 选择指定表中的所有字段。- 示例:wrapper.selectAll(User.class)
- selectAs(SFunction column, SFunction field): - 选择指定字段并将其映射到 DTO 的字段。- 示例:wrapper.selectAs(Department::getName, UserResponse::setDepartmentName)
2. 连接表
- leftJoin(Class joinClass, SFunction joinColumn, SFunction asColumn): - 左连接表。- 示例:wrapper.leftJoin(Department.class, Department::getId, User::getDepartmentId)
- rightJoin(Class joinClass, SFunction joinColumn, SFunction asColumn): - 右连接表。- 示例:wrapper.rightJoin(Department.class, Department::getId, User::getDepartmentId)
- innerJoin(Class joinClass, SFunction joinColumn, SFunction asColumn): - 内连接表。- 示例:wrapper.innerJoin(Department.class, Department::getId, User::getDepartmentId)
3. 查询条件
- eq(SFunction column, Object val): - 等于条件。- 示例:wrapper.eq(User::getId, 123)
- ne(SFunction column, Object val): - 不等于条件。- 示例:wrapper.ne(User::getId, 123)
- gt(SFunction column, Object val): - 大于条件。- 示例:wrapper.gt(User::getAge, 18)
- ge(SFunction column, Object val): - 大于等于条件。- 示例:wrapper.ge(User::getAge, 18)
- lt(SFunction column, Object val): - 小于条件。- 示例:wrapper.lt(User::getAge, 18)
- le(SFunction column, Object val): - 小于等于条件。- 示例:wrapper.le(User::getAge, 18)
- like(SFunction column, Object val): - 模糊查询(包含)。- 示例:wrapper.like(User::getName, "张三")
- notLike(SFunction column, Object val): - 模糊查询(不包含)。- 示例:wrapper.notLike(User::getName, "张三")
- in(SFunction column, Collection values): - IN 条件。- 示例:wrapper.in(User::getId, Arrays.asList(1, 2, 3))
- notIn(SFunction column, Collection values): - NOT IN 条件。- 示例:wrapper.notIn(User::getId, Arrays.asList(1, 2, 3))
- isNull(SFunction column): - IS NULL 条件。- 示例:wrapper.isNull(User::getEmail)
- isNotNull(SFunction column): - IS NOT NULL 条件。- 示例:wrapper.isNotNull(User::getEmail)
- between(SFunction column, Object val1, Object val2): - BETWEEN 条件。- 示例:wrapper.between(User::getAge, 18, 30)
- notBetween(SFunction column, Object val1, Object val2): - NOT BETWEEN 条件。- 示例:wrapper.notBetween(User::getAge, 18, 30)
4. 分组和排序
- groupBy(SFunction... columns): - 分组。- 示例:wrapper.groupBy(User::getAge)
- orderByAsc(SFunction... columns): - 升序排序。- 示例:wrapper.orderByAsc(User::getAge)
- orderByDesc(SFunction... columns): - 降序排序。- 示例:wrapper.orderByDesc(User::getAge)
5. 其他方法
- last(String sqlSegment): - 在 SQL 语句末尾添加自定义 SQL 片段。- 示例:wrapper.last("LIMIT 1")
- exists(String subQuery): - EXISTS 子查询。- 示例:wrapper.exists("SELECT 1 FROM department WHERE department.id = user.department_id")
- notExists(String subQuery): - NOT EXISTS 子查询。- 示例:wrapper.notExists("SELECT 1 FROM department WHERE department.id = user.department_id")
四.分页查询
1.添加配置类
/**
* 启用 MyBatis-Plus 的分页插件
*/
@Configuration
public class MyBatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
2.实现分页查询
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public List<Student> getList(StudentReq studentReq) {
// 创建一个 Page 对象,传入当前页码和每页显示的数量
// Page 对象是 MyBatis-Plus 提供的分页工具类,用于封装分页信息
Page<Student> page = new Page<>(studentReq.getPageNum(), studentReq.getPageSize());
// 调用 studentMapper 的 selectPage 方法进行分页查询
// 第一个参数是 Page 对象,第二个参数是查询条件(这里暂时没有条件,所以传入 null)
Page<Student> studentPage = studentMapper.selectPage(page, null);
// 获取分页结果中的记录列表
// getRecords 方法返回的是分页查询结果中的数据部分
return studentPage.getRecords();
}
}
版权归原作者 Love-Story 所有, 如有侵权,请联系我们删除。