还在用MyBatis写CRUD?这款神器帮你5分钟写后台管理基本功能2️⃣

举报
XiaoLin_Java 发表于 2022/02/22 15:11:42 2022/02/22
【摘要】 四、通用CRUD    我们之前学过,使用MyBatis-Plus的时候,Mapper接口里面的方法不需要我们再自己写了,只需要继承BaseMapper接口即可获取到各种各样的单表操作。 4.1、插入操作 4.1.1、方法定义    MyBatis-Plus中对于insert的方法定义是:/*** 插入一条记录** @param entity 实体对象*/int insert(T enti...

四、通用CRUD

    我们之前学过,使用MyBatis-Plus的时候,Mapper接口里面的方法不需要我们再自己写了,只需要继承BaseMapper接口即可获取到各种各样的单表操作。

image-20210426184057266

4.1、插入操作

4.1.1、方法定义

    MyBatis-Plus中对于insert的方法定义是:

/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);

4.1.2、测试

package cn.linstudy.test

import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

  @Autowired
  private UserMapper userMapper;

  @Test
  public void testInsert() {
    User user = new User();
    user.setAge(20);
    user.setEmail("test@itcast.cn");
    user.setName("曹操");
    user.setUserName("caocao");
    user.setPassword("123456");
    int result = this.userMapper.insert(user); //返回的result是受影响的行数,并不是自增后的id
    System.out.println("result = " + result);
    System.out.println(user.getId()); //自增后的id会回填到对象中
  }
}

4.2、更新操作

4.2.1、updateById

4.2.1.1、方法定义

/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);

4.2.1.2、测试



	// 需求: 将id=1用户名字修改为xiaolin

    @Test

    public void testUpdateById(){

        Employee employee = new Employee();
        employee.setId(1L);
        employee.setName("xiaolin");
        employeeMapper.updateById(employee);

    }

	// 注意: 拼接sql时,所有非null 字段都进行set 拼接

	// UPDATE employee SET name=?, age=?, admin=? WHERE id=?

	// 改进的方法是先查,再替换,最后更新

	// 需求: 将id=1用户名字修改为xiaolin

    @Test

    public void testUpdateById2(){

        Employee employee = employeeMapper.selectById(1L);

        employee.setName("xiaolin");

        employeeMapper.updateById(employee);

    }

4.2.2、update

4.2.2.1、方法定义

  /**
   * 根据 whereEntity 条件,更新记录
   *
   * @param entity        实体对象 (set 条件值,可以为 null)
   * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
   */
  int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T>
      updateWrapper);
	

4.2.2.2、测试

public class UserMapperTest {

  @Autowired
  private UserMapper userMapper;

  // 方法一:使用QueryWrapper
  @Test
  public void testUpdate() {
    User user = new User();
    user.setAge(22); //更新的字段
	//更新的条件
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("id", 6);
	//执行更新操作
    int result = this.userMapper.update(user, wrapper);
    System.out.println("result = " + result);
  }
    
   //方法二: 通过UpdateWrapper进行更新
    @Test
	public void testUpdate(){
		//更新的条件以及字段
    	UpdateWrapper<User> wrapper=new UpdateWrapper<>();
    	wrapper.eq("id",6).set("age",23);
		//执行更新操作
    	int result=this.userMapper.update(null,wrapper);
    	System.out.println("result = "+result);
    }
}

4.2.2.3、使用建议

  1. 知道id,并且所有更新使用updateById

  2. 部分字段更新,使用update

4.3、删除操作

4.3.1、deleteById

4.3.1.1、方法定义

/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);

4.3.1.2、测试

@Test
public void testDeleteById() {
	//执行删除操作
	int result = this.userMapper.deleteById(6L);
	System.out.println("result = " + result);
}

4.3.2、deleteByMap

4.3.2.1、方法定义

/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

4.3.2.2、测试

@Test
public void testDeleteByMap() {
	Map<String, Object> columnMap = new HashMap<>();
	columnMap.put("age",20);
	columnMap.put("name","张三");
	//将columnMap中的元素设置为删除的条件,多个之间为and关系
	int result = this.userMapper.deleteByMap(columnMap);
	System.out.println("result = " + result);
}

4.3.3、delete

4.3.3.1、方法定义

/**
* 根据 entity 条件,删除记录
*
* @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

4.3.3.2、测试

@Test
public void testDeleteByMap() {
	User user = new User();
	user.setAge(20);
	user.setName("张三");
	//将实体对象进行包装,包装为操作条件
	QueryWrapper<User> wrapper = new QueryWrapper<>(user);
	int result = this.userMapper.delete(wrapper);
	System.out.println("result = " + result);
}

4.3.4、deleteBatchIds

4.3.4.1、方法定义

/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable>
idList);

4.3.4.2、测试

@Test
public void testDeleteByMap() {
	//根据id集合批量删除
	int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));
	System.out.println("result = " + result);
}

4.4、查询操作

    MyBatis-Plus提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。

4.4.1、selectById

4.4.1.1、方法定义

/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);

4.1.1.2、测试

@Test
public void testSelectById() {
	//根据id查询数据
	User user = this.userMapper.selectById(2L);
	System.out.println("result = " + user);
}

4.4.2、selectBatchIds

4.4.2.1、方法定义

/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable>
idList);

4.2.2.2、测试

@Test
public void testSelectBatchIds() {
	//根据id集合批量查询
	List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
	for (User user : users) {
	System.out.println(user);
	}
}

4.4.3、selectOne

4.4.3.1、方法定义

/**
* 根据 entity 条件,查询一条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4.4.3.2、测试

@Test
public void testSelectOne() {
	QueryWrapper<User> wrapper = new QueryWrapper<User>();
	wrapper.eq("name", "李四");
	//根据条件查询一条数据,如果结果超过一条会报错
	User user = this.userMapper.selectOne(wrapper);
    System.out.println(user);
}

4.4.4、selectCount

4.4.4.1、方法定义

/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4.4.4.2、测试

@Test
public void testSelectCount() {
	QueryWrapper<User> wrapper = new QueryWrapper<User>();
	wrapper.gt("age", 23); //年龄大于23岁
    Integer count = this.userMapper.selectCount(wrapper);
	System.out.println("count = " + count);
}

4.4.5、selectList

4.4.5.1、方法定义

/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4.4.5.2、测试

@Test
public void testSelectList() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 23); //年龄大于23岁
    //根据条件查询数据
	List<User> users = this.userMapper.selectList(wrapper);
	for (User user : users) {
	System.out.println("user = " + user);
	}
}

4.4.6、selectPage

4.4.6.1 方法定义

/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4.4.6.2、配置分页插件

@Configuration
@MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
	}
}

4.4.6.3、测试

@Test
public void testSelectPage() {
	QueryWrapper<User> wrapper = new QueryWrapper<User>();
	wrapper.gt("age", 20); //年龄大于20岁
	Page<User> page = new Page<>(1,1);
	//根据条件查询数据
	IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
	System.out.println("数据总条数:" + iPage.getTotal());
	System.out.println("总页数:" + iPage.getPages());
	List<User> users = iPage.getRecords();
	for (User user : users) {
	System.out.println("user = " + user);
	}
}	

4.4.7、SQL注入原理

    MP在启动后会将BaseMapper中的一系列的方法注册到meppedStatements中,那么究竟是如何注入的呢?流程又是怎么样的?

    在MP中,ISqlInjector负责SQL的注入工作,它是一个接口,AbstractSqlInjector是它的实现类,实现关系如下:

image-20210428142720554

    在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的:

@Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?>
mapperClass) {
	Class<?> modelClass = extractModelClass(mapperClass);
	if (modelClass != null) {
		String className = mapperClass.toString();
		Set<String> mapperRegistryCache =
		GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
	if (!mapperRegistryCache.contains(className)) {
		List<AbstractMethod> methodList = this.getMethodList();
		if (CollectionUtils.isNotEmpty(methodList)) {
			TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant,
modelClass);
			// 循环注入自定义方法
			methodList.forEach(m -> m.inject(builderAssistant, mapperClass,
modelClass, tableInfo));
		} else {	
            logger.debug(mapperClass.toString() + ", No effective injection method
was found.");
			}
			mapperRegistryCache.add(className);
		}
	}
}	

image-20210428164123430

    以SelectById为例查看:

public class SelectById extends AbstractMethod {
	@Override
	public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?>
modelClass, TableInfo tableInfo) {
		SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;
		SqlSource sqlSource = new RawSqlSource(configuration,
String.format(sqlMethod.getSql(),
		sqlSelectColumns(tableInfo, false),
		tableInfo.getTableName(), tableInfo.getKeyColumn(),
		tableInfo.getKeyProperty(),
		tableInfo.getLogicDeleteSql(true, false)), Object.class);
		return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(),
sqlSource, modelClass, tableInfo);
	}
}

    可以看到,生成了SqlSource对象,再将SQL通过addSelectMappedStatement方法添加到meppedStatements中。

image-20210428164932955

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。