# Mybatis-Plus 框架
# 1. 写在前面的话
我个人不太喜欢使用 MyBatis-Plus 。原因在于:它只解决掉了一部分问题,而且在它所解决的问题的领域内,它还不是唯一方案。
简单来说就是这样:
数据库操作的 “简单问题” ,MyBatis 解决;
数据库操作的 “简单的复杂问题” ,MyBatis-Plus / Tk-Mapper / Example 等方案可以帮忙解决;
数据库操作的 “复杂的复杂问题” ,还得回到 MyBatis 中用笨办法解决。
个人觉得有点 “食之无味,弃之可惜” 的感觉。
那么为什么 Mybatis-Plus 好像用的还蛮广泛?
MyBatis 在国内的使用率远高于国外,而 MyBatis-Plus 又是国人做的,因此 MyBatis-Plus 在国人的 MyBatis 圈子中曝光度还是很高的,基本上仅次于 MyBatis 的分页插件 PageHelper 。所以,无论你用不用 Mybatis-Plus ,你肯定是听说过它的。
虽然 MyBatis-Plus 等一干方案仅仅只能简化 MyBatis 的一部分复杂操作,但是基于 “聊胜于无” 的考虑,能偷多少懒就偷多少懒,因此,这一批方案总还是有人会考虑去选一个用的,否则 “一点懒都不偷” 不符合人性。
MyBatis-Plus 的出现和宣传比它的竞品们都要早,出于 “先发” 优势,在这一批方案中 “最出名” 的也就是 MyBatis-Plus 了。无论你考虑用哪一个,MyBatis-Plus 一定是你的备选项之一,它出现概率高,那么被选中的概率自然也就高了。
回到我个人的观点,相较于 MyBatis-Plus ,我更倾向于使用 Example 。原因在于:它是官方提出的解决方案,并且使用它没有引入任何额外的包。
TIP
对于包、方案的选择问题,我个人一贯的观点是:能用官方包,就不要使用第三方包;能用官方推荐第三方包,就不要使用其它第三方包。
# 2. 入门
引入 maven 依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency>
如果你使用的是阿里云的 spring initializer ,你可以在直接去选择 myabtis-plus 。
定义 PO 类,并标注注解
@Data @TableName("department") public class Department { @TableId(value = "id", type = IdType.AUTO) private Long id; @TableField(value = "name", jdbcType = JdbcType.VARCHAR) private String name; @TableField(value = "location", jdbcType = JdbcType.VARCHAR) private String location; }
定义 Mapper 接口,要求继承自特定父接口:
public interface DepartmentDao extends BaseMapper<Department> { }
因为我们的自定义接口继承了mybatis-plus 的接口,因此我们的接口中自然 “天生就有” 若干方法。
配置 mybatis 包扫描,扫描 mapper 接口所在位置
@SpringBootApplication @MapperScan(basePackages = "com.example.mybatisplusdemo.outlet.dao") public class MybatisPlusDemoApplication { ... }
使用
@Resource private DepartmentDao dao; @Test public void demo1() { Wrapper<Department> eq = new QueryWrapper<Department>().eq("id", 1L); System.out.println(dao.selectOne(eq)); }
# 3. Mapper CRUD 接口
Mapper CRUD 接口 (opens new window)
除了基本的 CRUD 操作,mybatis-plus 带来的简便之处是简化了条件查询。
# 4. 条件查询
按用户名和状态查询后台用户并按创建时间降序排列为例。SQL 实现如下:
SELECT *
FROM employee
WHERE department_id = 2
AND salary BETWEEN 500 AND 3000
ORDER BY salary DESC;
在 mybatis-plus 中创建 Wrapper 对象,并调用对象的方法,例如,eq()
、between()
等方法来表达你所想的查询条件。这些条件之间是 AND 的关系:
@Data
@TableName("employee")
public class Employee {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "name", jdbcType = JdbcType.VARCHAR)
private String name;
@TableField(value = "job", jdbcType = JdbcType.VARCHAR)
private String job;
@TableField(value = "manager_id", jdbcType = JdbcType.BIGINT)
private Long managerId;
@TableField(value = "hire_date", jdbcType = JdbcType.DATE)
private Date hireDate;
@TableField(value = "salary", jdbcType = JdbcType.INTEGER)
private Integer salary;
@TableField(value = "commission", jdbcType = JdbcType.INTEGER)
private Integer commissoin;
@TableField(value = "department_id", jdbcType = JdbcType.BIGINT)
private Long departmentId;
}
Wrapper<Employee> wp1 = new QueryWrapper<Employee>()
.eq("department_id", 2L)
.between("salary", 500, 3000)
.orderByDesc("salary");
employeeDao.selectList(wp1).forEach(System.out::println);
# 5. 逻辑条件的组合
逻辑条件的组合大体分为 2 种:
单纯的
...与...与...
/...或...或...
与或
混用,由于或
的优先级更高,因此可以改造成(... and ...) or (... and ...) or ...
这样的统一形式。
# 与与和或或
...与...与...
情况:如上例所示,QueryWrapper 的链式调用中,所表达的逻辑关系就是 and 的关系。
...或...或...
情况:这种关系中,在 Wrapper 对象的链式调用中穿插调用
or()
方法即可。or()
方法前后的条件就是或的关系。Wrapper<Employee> wp1 = new QueryWrapper<Employee>() .lt("salary", 1000) .or() .isNotNull("commission"); employeeDao.selectList(wp1).forEach(System.out::println);
# 与或混用
与或
混用的情况下,先要把你『心里』的 SQL 语句改造成通用形式:(... and ...) or (... and ...) or ...
。
Wrapper<Employee> wrapper = new QueryWrapper<Employee>()
.eq("department_id", 2L)
.lt("salary", 1500)
.or()
.eq("department_id", 3L)
.gt("salary", 1300);
employeeDao.selectList(wrapper).forEach(System.out::println);
# 6. 条件删除
我们『心里』期望执行的 SQL 如下:
DELETE FROM department WHERE name = 'test';
使用 Wrapper 对应 Java 中的实现如下:
Wrapper<Department> wrapper = new QueryWrapper<Department>().eq("name", "test");
departmentDao.delete(wrapper);
# 7. 条件修改
我们『心里』期望执行的 SQL 如下:
update
department
set name = 'hello-new',
location = 'world'
where
name = 'hello';
使用 Wrapper 对应 Java 中的实现如下:
Department department = new Department(null, "hello-new", "world");
Wrapper<Department> wrapper = new QueryWrapper<Department>()
.eq("name", "hello");
departmentDao.update(department, wrapper);
注意,这里的 null 值表示保持原址不变。