三、基本CRUD操作
上一节我们完成了mybatis-plus
的集成,也已经在mp01
中添加相关的实体类的对应的数据库表,这一节我们来实现基于mybatis-plus
的CRUD操作。
首先按照上一节的操作,新建一个mp02
的 Module
,可以将mp01
中的内容全部复制过来,同时进行一下修改:
修改 Employee
实体类:
/**
* mybatis-plus默认会使用实体类的小写类名作为表名
*/
@Data
@ToString
//@TableName(value = "https://www.it610.com/article/tbl_employee")// ==> 全局的表前缀策略配置
public class Employee {/**
* @TableId:
*value: 指定表中的主键的列名,如果实体属性名与列名一致,可以省略不指定
*type:指定主键策略
* 设置主键自增
*/
//@TableId(value = "https://www.it610.com/article/id", type = IdType.AUTO) // ==> 全局表主键生成策略private Integer id;
@TableField(value = "https://www.it610.com/article/last_name")
private String lastName;
private String email;
private Integer gender;
private Integer age;
// 当前字段是否在数据库中存在,如果不存在则忽略该字段插入到数据库中
@TableField(exist = false)
private Double salary;
}
修改
applicationContext.xml
文件,添加下面的内容:
完整的xml文件如下:
在
mp02\src\main\java\com\mp\mapper\EmployeeMapper.java
路径下新建 EmployeeMapper.java
mapper文件,EmployeeMapper
类需要继承 BaseMapper
,代码如下: /**
* @description: mapper接口
* 实现方式:
* 基于 Mybatis
*需要编写 EmployeeMapper 接口,并手动编写 CRUD 方法
*提供 EmployeeMapper.xml 映射文件,并手动编写每个方法对应的 SQL 语句.
*
* 基于 MP
*只需要创建 EmployeeMapper 接口, 并继承 BaseMapper 接口.这就是使用 MP
*需要完成的所有操作,甚至不需要创建 SQL 映射文件。
*BaseMapper:泛型指定的就是当前mapper接口所操作的实体类型
*/
public interface EmployeeMapper extends BaseMapper {// 使用 mybatis 插入数据时获取主键值
//IntegerinsertEmployee(Employee employee );
// SQL...
}
修改mp02的
pom.xml
文件:mybatis-plus-in-action
com.demo.mybatis-plus
1.0-SNAPSHOT
4.0.0 mp02
com.baomidou
mybatis-plus
${mybatis.plus.version}
junit
junit
${junit.version}
log4j
log4j
${log4j.version}
com.alibaba
druid
${druid.version}
mysql
mysql-connector-java
${mysql.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-orm
${spring.version}
org.projectlombok
lombok
${lombok.version}
provided
上面的准备工作做完了,下面我们可以来进行CRUD操作了:
1、insert操作
/**
* 通用 插入操作
*/
@Test
public void testCommonInsert() {
// 初始化employee 对象
Employee employee = new Employee();
employee.setLastName("MP");
employee.setEmail("mp@github.com");
employee.setGender(1);
employee.setAge(22);
employee.setSalary(2000.0);
// 插入到数据库 insert方法在插入时, 会根据实体类的每个属性进行非空判断,只有非空的属性对应的字段才会出现到SQL语句中
int ret = employeeMapper.insert(employee);
System.out.println("result:" + ret);
// 获取当前数据在数据库中的主键值
Integer key = employee.getId();
System.out.println("key:" + key);
}
2、update操作
/**
* 通用更新操作
*/
@Test
public void testCommonUpdate() {
// 初始化employee 对象
Employee employee = new Employee();
employee.setId(19);
employee.setLastName("MP");
employee.setEmail("mybatis-plus@github.com");
employee.setGender(0);
// employee.setAge(33);
// 没有传的字段不会被更新// 单个更新
Integer result = employeeMapper.updateById(employee);
System.out.println("result:" + result);
// 批量更新, 如果 Wrapper 为空,则全部更新
result = employeeMapper.update(employee, null);
System.out.println("result:" + result);
}
3、select操作
/**
* 通用查询操作
*/
@Test
public void testCommonSelect() {
// 1、通过id查询
Employee employee = employeeMapper.selectById(14);
System.out.println(employee);
// 2、通过多个列查询 id+lastName
Employee employee1 = new Employee();
employee1.setId(13);
employee1.setLastName("White");
Wrapper employeeWrapper = new QueryWrapper(employee1);
Employee selectOne = employeeMapper.selectOne(employeeWrapper);
System.out.println(selectOne);
// 3、通过多个id进行查询
List idList = new ArrayList();
idList.add(11);
idList.add(12);
idList.add(13);
idList.add(14);
List employeeList = employeeMapper.selectBatchIds(idList);
System.out.println("employeeList:" + employeeList);
// 4、通过 selectMaps 查询
Map columnMap = new HashMap();
columnMap.put("last_name", "White");
columnMap.put("gender", 0);
List selectByMap = employeeMapper.selectByMap(columnMap);
System.out.println("selectByMap:" + selectByMap);
// 5、分页查询 selectPage 使用分页查询需要在 applicationContext.xml 中添加 分页查询插件 配置
IPage employeeIPage = employeeMapper.selectPage(new Page<>(2, 1), null);
System.out.println("employeeIPage:" + employeeIPage.getRecords());
}
注意:
1、columnMap中使用的是数据库中的字段名,而不是实体类的字段名
2、分页查询操作需要在
applicationContext.xml
中添加分页插件,完整代码可以看前面的完整配置:
4、delet操作
/**
* 通用删除操作
*/
@Test
public void testCommonDelete() {
// 1、根据id删除
Integer result = employeeMapper.deleteById(15);
System.out.println("result:" + result);
// 2、根据 deleteByMap 条件删除
Map columnMap= new HashMap<>();
columnMap.put("last_name","MP");
columnMap.put("email","mybatis-plus@github.com");
Integer ret = employeeMapper.deleteByMap(columnMap);
System.out.println("ret:" + ret);
// 3、批量删除
List idList = new ArrayList();
idList.add(18);
idList.add(19);
Integer deleteResult = employeeMapper.deleteBatchIds(idList);
System.out.println("deleteResult:" + deleteResult);
}
注意:
columnMap中使用的是数据库中的字段名,而不是实体类的字段名5、完整测试代码
public class TestMp {
private ApplicationContext ioc = new
ClassPathXmlApplicationContext("applicationContext.xml");
private EmployeeMapper employeeMapper = ioc.getBean("employeeMapper", EmployeeMapper.class);
/**
* 通用删除操作
*/
@Test
public void testCommonDelete() {
// 1、根据id删除
Integer result = employeeMapper.deleteById(15);
System.out.println("result:" + result);
// 2、根据 deleteByMap 条件删除
Map columnMap= new HashMap<>();
columnMap.put("last_name","MP");
columnMap.put("email","mybatis-plus@github.com");
Integer ret = employeeMapper.deleteByMap(columnMap);
System.out.println("ret:" + ret);
// 3、批量删除
List idList = new ArrayList();
idList.add(18);
idList.add(19);
Integer deleteResult = employeeMapper.deleteBatchIds(idList);
System.out.println("deleteResult:" + deleteResult);
}/**
* 通用查询操作
*/
@Test
public void testCommonSelect() {
// 1、通过id查询
Employee employee = employeeMapper.selectById(14);
System.out.println(employee);
// 2、通过多个列查询 id+lastName
Employee employee1 = new Employee();
employee1.setId(13);
employee1.setLastName("White");
Wrapper employeeWrapper = new QueryWrapper(employee1);
Employee selectOne = employeeMapper.selectOne(employeeWrapper);
System.out.println(selectOne);
// 3、通过多个id进行查询
List idList = new ArrayList();
idList.add(11);
idList.add(12);
idList.add(13);
idList.add(14);
List employeeList = employeeMapper.selectBatchIds(idList);
System.out.println("employeeList:" + employeeList);
// 4、通过 selectMaps 查询
Map columnMap = new HashMap();
columnMap.put("last_name", "White");
columnMap.put("gender", 0);
List selectByMap = employeeMapper.selectByMap(columnMap);
System.out.println("selectByMap:" + selectByMap);
// 5、分页查询 selectPage 使用分页查询需要在 applicationContext.xml 中添加 分页查询插件 配置
IPage employeeIPage = employeeMapper.selectPage(new Page<>(2, 1), null);
System.out.println("employeeIPage:" + employeeIPage.getRecords());
}/**
* 通用更新操作
*/
@Test
public void testCommonUpdate() {
// 初始化employee 对象
Employee employee = new Employee();
employee.setId(19);
employee.setLastName("MP");
employee.setEmail("mybatis-plus@github.com");
employee.setGender(0);
//employee.setAge(33);
// 单个更新
Integer result = employeeMapper.updateById(employee);
System.out.println("result:" + result);
// 批量更新, 如果 Wrapper 为空,则全部更新
result = employeeMapper.update(employee, null);
System.out.println("result:" + result);
}/**
* 通用 插入操作
*/
@Test
public void testCommonInsert() {
// 初始化employee 对象
Employee employee = new Employee();
employee.setLastName("MP");
employee.setEmail("mp@github.com");
employee.setGender(1);
employee.setAge(22);
employee.setSalary(2000.0);
// 插入到数据库 insert方法在插入时, 会根据实体类的每个属性进行非空判断,只有非空的属性对应的字段才会出现到SQL语句中
int ret = employeeMapper.insert(employee);
System.out.println("result:" + ret);
// 获取当前数据在数据库中的主键值
Integer key = employee.getId();
System.out.println("key:" + key);
}@Test
public void testEnvironment() throws Exception {
DataSource ds = ioc.getBean("dataSource", DataSource.class);
Connection conn = ds.getConnection();
System.out.println(conn);
}
}
完成上面的操作后,mp02的代码结构如下所示:
文章图片
mp02-01.png 6、Mybatis-Plus启动注入SQL原理分析
6.1、问题: 在我们使用 BaseMapper 提供的方法来进行CRUD操作的时候,有没有想过为什么我们能直接使用这些方法,而这些方法又是什么时候加载到容器中呢?
xxxMapper 继承了 BaseMapper, BaseMapper 中提供了通用的 CRUD 方法,这些方法来源于 BaseMapper, 有方法就必须有 SQL, 因为 MyBatis 最终还是需要通过SQL 语句操作数据。以为 Mybatis-Plus 是在MyBatis 的基础上做了增强,所以我们有必要了解一些前置知识:
MyBatis 源码中比较重要的一些对象, MyBatis 框架的执行流程
Configuration
:MyBatis 的全局配置对象 MappedStatement
:MappedStatement保存所有的SQL方法和执行语句 ……..6.2、通过现象看到本质: 通过debug日志我们可以看到,在我们执行 employeeMapper.deleteById(id)方法之前,Mybatis-Plus已经帮我们把 BaseMapper 中内置的方法就加载到了MappedStatement中。
文章图片
x01.png 我们在 employeeMapper.deleteById(id)方法中打下断点,可以看到
A.
employeeMapper
的本质是com.baomidou.mybatisplus.core.override.MybatisMapperProxy
,如果是mybatis 则看到的是 org.apache.ibatis.binding.MapperProxy
B. MapperProxy 中两个重要对象
sqlSession
–>SqlSessionFactory
文章图片
C.
SqlSessionFacotry
中又有两个重要的对象 Configuration
→ MappedStatements
文章图片
x03.png 每一个 mappedStatement 都表示 Mapper 接口中的一个方法与 Mapper 映射文件中的一个 SQL。
文章图片
x04.png Mybatis-Plus 在启动就会挨个分析 xxxMapper 中的方法,并且将对应的 SQL 语句处理好,保存到
configuration
对象中的 mappedStatements
中. D. 本质: Configuration
: MyBatis 或者 MP 全局配置对象MappedStatement
:一个 MappedStatement 对象对应 Mapper 配置文件中的一个select/update/insert/delete 节点,主要描述的是一条 SQL 语句 SqlMethod
: 枚举对象 , MP 支持的 SQL 方法 TableInfo
: 数据库表反射信息 ,可以获取到数据库表相关的信息 SqlSource
: SQL 语句处理对象 MapperBuilderAssistant
: 用于缓存、 SQL 参数、查询方剂结果集处理等,通过 MapperBuilderAssistant 将每一个 mappedStatement添加到 configuration 中的 mappedstatements 中 。在下图所示的位置处打断点,可以观测到MP加载内置方法的整个过程,我们在后边自定义全局操作添加自定义方法的时候,还会碰到
AbstractMethod
对象和AbstractSqlInjector
对象,文章图片
x05-MapperFactoryBean.png
文章图片
x06-MybatisMapperRegistry.png
文章图片
x07-MybatisMapperAnnotationBuilder.png
文章图片
x08-AbstractSqlInjector.png
文章图片
x09-AbstractMethod.png
文章图片
x10-Insert.png
文章图片
x11-AbstractMethod-addMappedStatement.png
文章图片
x12-MapperBuilderAssistant-addMappedStatement.png
文章图片
x13-MybatisConfiguration-addMappedStatement.png Mybatis-Plus启动注入SQL的执行流程入下入所示(中间省略若干非关键步骤):
文章图片
xx-01.png
文章图片
xx-02.png 以上是基本的 CRUD 操作, 你所见,我们仅仅需要继承一个 BaseMapper 即可实现大部分单表 CRUD 操作。 BaseMapper 提供了多达 17 个方法给大家使用, 可以极其方便的实现单一、批量、分页等操作。 极大的减少开发负担。
综上,基于
mybatis-plus
的CRUD演示就完成了,现有一个需求,我们需要分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢?MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL,并基于 PageHelper 插件完成分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。 普通的 Mapper能够解决这类痛点吗? MP: 依旧不用编写 SQL 语句, MP 提供了功能强大的条件构造器
AbstractWrapper
。下面我们就可以进入到下一节AbstractWrapper条件构造器
了。源代码
【三、基本CRUD操作】相关示例完整代码:mybatis-plus-in-action
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 第三节|第三节 快乐和幸福(12)
- android第三方框架(五)ButterKnife
- 一个人的碎碎念
- 野营记-第五章|野营记-第五章 讨伐梦魇兽
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- Shell-Bash变量与运算符
- 三十年后的广场舞大爷