二、MyBatis Plus 的 CRUD
2.5 MP 的 update 相关方法
//根据 ID 修改 int updateById(@Param(Constants.ENTITY) T entity); //根据 whereEntity 条件,更新记录 int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); 复制代码
在TeslaMapperTest中增加测试方法updateById
@Test public void updateById(){ Tesla updateTesla = new Tesla(); updateTesla.setId(5); updateTesla.setVehicleName("Model 3P"); int count = teslaMapper.updateById(updateTesla); System.out.println("更新的行数为:" + count); } 复制代码
执行测试方法
id为5的数据成功修改,UPDATE语句中只出现了代码中设置了属性值的属性,修改属性时会进行非空判断,只修改非空的属性值。
2.6 MP 的 select 相关方法
基本查询
/** * 根据 ID 查询 * * @param id 主键ID */ T selectById(Serializable id); /** * 查询(根据ID 批量查询) * * @param idList 主键ID列表(不能为 null 以及 empty) */ List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); /** * 查询(根据 columnMap 条件) * * @param columnMap 表字段 map 对象 */ List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); 复制代码
在TeslaMapperTest中分别新增selectBatchIds、selectByMap 两个测试方法
@Test public void selectBatchIds(){ Collection<Integer> batchIds = new HashSet<>(); // 构造查询的id的集合 for (int i = 0; i < 5; i++) { batchIds.add(i); } List<Tesla> teslaList = teslaMapper.selectBatchIds(batchIds); // 遍历查询到的数据 for (Tesla tesla : teslaList) { System.out.println("查询到的内容为:" + tesla); } } @Test public void selectByMap(){ Map<String, Object> conditionMap = new HashMap<>(); // 构造查询条件,key为查询条件,value为查询条件的值 conditionMap.put("factory","Fremont Gigafactory"); conditionMap.put("name","Model S"); List<Tesla> teslaList = teslaMapper.selectByMap(conditionMap); for (Tesla tesla : teslaList) { System.out.println("selectByMap方法查询到的数据:" + tesla); } } 复制代码
再增加一个name条件
conditionMap.put("name","Model S"); 复制代码
SQL语句中自动添加了AND关键字
Map条件查询所使用的Key是数据库中的字段名,不是实体类的属性名。
分页查询
/** * 根据 entity 条件,查询全部记录(并翻页) * * @param page 分页查询条件(可以为 RowBounds.DEFAULT) * @param queryWrapper 实体对象封装操作类(可以为 null) */ <P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); /** * 根据 Wrapper 条件,查询全部记录(并翻页) * * @param page 分页查询条件 * @param queryWrapper 实体对象封装操作类 */ <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 复制代码
MyBatis Plus提供了两个分页查询的方法,两个方法中都有一个Wrapper <T> 参数,Warpper是MP中的条件构造器,在 Data Access 之 MyBatis Plus(二)- Wrapper 条件构造器 会提到,这里先设置为null
selectPage方法入参中另外一个参数是一个IPage的实现类;可以使用IPage的实现类Page作为分页查询的页面配置
Page提供了几个构造函数以及一些获取当前页、判断是否有上一页或下一页以及总页数总记录数等方法
在TeslaMapperTest中增加分页测试方法
@Test public void selectPage(){ Page<Tesla> teslaPage = new Page<>(2,4); Page<Tesla> page = teslaMapper.selectPage(teslaPage, null); System.out.println("--------------------"); System.out.println("查询当前页面的数据:" + page.getRecords()); System.out.println("--------------------"); } 复制代码
执行测试
根据控制台输出的SQL语句可以看出并没有执行分页查询,这是因为缺少MyBatis Plus的分页插件导致的。
MyBatis Plus分页插件配置
在application.xml中新增分页插件配置
<!--配置分页插件--> <bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"> <property name="dbType" value="MYSQL"></property> </bean> <!--配置拦截器--> <bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"> <property name="interceptors" ref="paginationInnerInterceptor"></property> </bean> 复制代码
然后在MyBatis Plus的MybatisSqlSessionFactoryBean中添加配置的拦截器
<bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <!--其他配置保持不变--> <!--设置使用分页插件,否则分页会失效--> <property name="plugins" ref="mybatisPlusInterceptor"></property> </bean> 复制代码
再次执行selectPage测试方法
根据控制台的输出的SQL语句及数据可以确定,MyBatis Plus分页生效
selectMapsPage
在TeslaMapperTest测试类中增加测试方法selectMapsPage
@Test public void selectMapsPage(){ Page<Map<String,Object>> teslaPage = new Page<>(2,4); Page<Map<String, Object>> mapPage = teslaMapper.selectMapsPage(teslaPage, null); System.out.println("--------------------"); System.out.println("查询当前页面的数据:" + mapPage.getRecords()); System.out.println("--------------------"); } 复制代码
执行方法的测试
根据输出的结果可以确定,selectMapsPage方法返回的是Map类型的数据,而selectPage返回的是封装好的实体类对象。
2.7 MP 的 delete 相关方法
/** * 根据 ID 删除 * * @param id 主键ID */ int deleteById(Serializable id); /** * 根据实体(ID)删除 * * @param entity 实体对象 * @since 3.4.4 */ int deleteById(T entity); /** * 根据 columnMap 条件,删除记录 * * @param columnMap 表字段 map 对象 */ int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); /** * 删除(根据ID或实体 批量删除) * * @param idList 主键ID列表或实体列表(不能为 null 以及 empty) */ int deleteBatchIds(@Param(Constants.COLLECTION) Collection<?> idList); 复制代码
在TeslaMapperTest中新增四个测试方法
@Test public void deleteByIdWithInteger(){ int id = 1166057479; int count = teslaMapper.deleteById(id); System.out.println("根据ID删除,更新行数为:" + count); } @Test public void deleteByIdWithEntity(){ Tesla tesla = new Tesla(); tesla.setId(1166057478); int count = teslaMapper.deleteById(tesla); System.out.println("根据Entity删除,更新行数为:" + count); } @Test public void deleteByMap(){ Map<String,Object> map = new HashMap<>(); map.put("factory","Texas Cybertruck Gigafactory"); int count = teslaMapper.deleteByMap(map); System.out.println("根据Map删除,更新行数为:" + count); } @Test public void deleteByBachIds(){ List<Integer> idList = new ArrayList<>(); for (int i = 1166057474; i < 1166057478; i++) { idList.add(i); } Integer count = teslaMapper.deleteBatchIds(idList); System.out.println("根据idList删除,更新行数为:" + count); } 复制代码
执行deleteByIdWithInteger方法
根据控制台的输出可以确定是根据传入的ID为条件执行删除操作
执行deleteByIdWithEntity方法
传入了设置id属性的实体类和直接传入id的效果是相同的
执行deleteByMap方法
Map中设置了SQL语句中WHERE子句后面的条件,可以根据设置的条件执行删除,这个条件的Key一定要是数据库中的字段
执行deleteByBachIds方法
成功删除idList中指定的数据
三、MyBatis Plus 启动注入 SQL 的原理
MyBatis的一大特性就是损耗小,启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,我们可以在deleteByIdWithInteger方法的teslaMapper.deleteById(id)这一行打断点,启动Debug模式
TeslaMapper接口的本质是代理类MyBatisMapperProxy;查看MyBatisMapperProxy源码,代理类中也包含了一个sqlSession属性
TeslaMapper代理类中自然也包含了sqlSession
并且在mappedStatement中包含了方法与映射文件中的SQL,MyBatis启动就会将对应方法和SQL语句处理包,保存到configuration对象中的mappedStatements中。
MyBatis Plus中的关键对象:
- Configuration: MyBatis 或者 MP 全局配置对象
- MappedStatement:一个 MappedStatement 对象对应 Mapper 配置文件中的一个 select/update/insert/delete 节点,主要描述的是一条 SQL 语句
- SqlMethod : 枚举对象 ,MP 支持的 SQL 方法
- TableInfo:数据库表反射信息 ,可以获取到数据库表相关的信息
- SqlSource: SQL 语句处理对象
- MapperBuilderAssistant: 用于缓存、SQL 参数、查询方剂结果集处理等,通过 MapperBuilderAssistant 将每一个 mappedStatement 添加到 configuration 中的 mappedstatements 中