Mybatis-Plus 通用CRUD的详细操作

目录
  • 1、插入操作
    • 1.1 方法定义
    • 1.2 测试用例
    • 1.3 测试
    • 1.4 @TableField
  • 2、更新操作
    • 2.1 根据id更新
    • 2.2 根据条件更新
  • 3、删除操作
    • 3.1 deleteById
    • 3.2 deleteByMap
    • 3.3 delete
    • 3.4 deleteBatchIds
  • 4、查询操作
    • 4.1 selectById
    • 4.2 selectBatchIds
    • 4.3 selectOne
    • 4.4 selectCount
    • 4.5 selectList
    • 4.6 selectPage
  • 5 SQL注入的原理

通过前面的学习,我们了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这些
操作。

1、插入操作

1.1 方法定义

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

1.2 测试用例

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

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert(){
        User user=new User();
        user.setAge(12);
        user.setName("曹操");
        user.setPassword("123");
        user.setMail("caocao@qq.com");
        user.setUserName("曹操");
        user.setAddress("北京");
        //result数据库受影响的行数
        int result = userMapper.insert(user);
        System.out.println("result=>"+result);
        //获取自增长后的id值
        System.out.println(user.getId());//自增后的id会回填到对象中
    }
}    

1.3 测试

可以看到,数据已经写入到了数据库,但是,id的值不正确,我们期望的是数据库自增长,实际是MP生成了id的值
写入到了数据库。

如何设置id的生成策略呢?

MP支持的id策略

package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 全局唯一ID (idWorker)
     */
    ID_WORKER(3),
    /**
     * 全局唯一ID (UUID)
     */
    UUID(4),
    /**
     * 字符串全局唯一ID (idWorker 的字符串表示)
     */
    ID_WORKER_STR(5);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

修改User对象:

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {
    @TableId(value="id",type= IdType.AUTO)//设置id字段为自增长
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
}

数据插入成功:

1.4 @TableField

在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个:

1、对象中的属性名和字段名不一致的问题(非驼峰)

2、对象中的属性字段在表中不存在的问题

使用:

其他用法,如密碼字段不加入查询字段:

效果:

.

2、更新操作

在MP中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。

2.1 根据id更新

方法定义:

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

测试:

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

@Autowired private UserMapper userMapper; 

@Test
public void testUpdateById() {
	User user = new User(); user.setId(6L); //主键
	user.setAge(21); //更新的字段
	//根据id更新,更新不为null的字段
	this.userMapper.updateById(user);
} 

}

结果:

2.2 根据条件更新

方法定义:

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

测试用例:

@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);
}

测试结果:

均可达到更新的效果。

关于wrapper更多的用法后面会详细讲解。

3、删除操作

3.1 deleteById

方法定义:

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

测试用例:

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

数据被删除。

3.2 deleteByMap

方法定义:

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

测试用例:

@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);
}

3.3 delete

方法定义:

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

测试用例:

@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);
}

结果:

3.4 deleteBatchIds

方法定义:

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

测试用例:

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

结果:

4、查询操作

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

4.1 selectById

方法定义:

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

测试用例:

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

结果:

4.2 selectBatchIds

方法定义:

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

测试用例:

@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.3 selectOne

方法定义:

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

测试用例:

@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 selectCount

方法定义:

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

测试用例:

@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.5 selectList

方法定义:

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

测试用例:

@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.6 selectPage

方法定义:

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

配置分页插件:

package cn.itcast.mp;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 

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

测试用例:

@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);
	}
}

结果:

5 SQL注入的原理

前面我们已经知道,MP在启动后会将BaseMapper中的一系列的方法注册到mappedStatements中,那么究竟是如
何注入的呢?流程又是怎么样的?下面我们将一起来分析下。

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

在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);
            }
        }
    }

在实现方法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo)); 是关键,循环遍历方法,进行注入。

最终调用抽象方法injectMappedStatement进行真正的注入:

 /**
     * 注入自定义 MappedStatement
     *
     * @param mapperClass mapper 接口
     * @param modelClass  mapper 泛型
     * @param tableInfo   数据库表反射信息
     * @return MappedStatement
     */
    public abstract MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo);

查看该方法的实现:

以SelectById为例查看:

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

到此这篇关于Mybatis-Plus 通用CRUD的文章就介绍到这了,更多相关Mybatis-Plus 通用CRUD内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-09-12

MyBatis-Plus使用ActiveRecord(AR)实现CRUD

目录 1.什么是ActiveRecord(AR)? 2.通过AR实现CRUD 1.1 insert 1.2 update 1.3 delete 1.4 select 1.什么是ActiveRecord(AR)? ActiveRecord 是什么: 每一个数据库表应该对应创建一个实体类,类的每一个对象的实例对应于数据库中表的一行记录; 通常表的每个字段在类中都有相应的方法Field; ActiveRecord 负责把自己持久化. 在 ActiveRecord 中封装了对数据库的访问,通过对象自己实

springboot+mybatis-plus实现内置的CRUD使用详解

springboot+mybatis-plus实现内置的CRUD使用详情,具体修改删除操作内容后文也有详细说明 mybatis-plus的特性 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作 强大的 CRUD操作:内置通用 Mapper.通用Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda形式调用:通过 Lambda 表达式,方

基于Mybatis-Plus的CRUD的实现

使用mybatis-plus自动生成了5个模块(xml/bean/mapper/service/controller)的代码,这里练习一下mybatis-plus框架下的CRUD. 还是原先的那个springboot项目. mybatis-plus也是mybatis的增强版,它并未改变mybatis原有功能,只是在传统mybatis原有基础上又新增了一些功能,用以提高开发效率. 比如,在mybatis-plus框架下,项目mapper层接口可通过继承BaseMapper,获取基本的CRUD功能,

基于mybatis高级映射多对多查询的实现

1.同以前一样,首先给一个使用多对多的需求, 要查询用户以及用户所购买的商品信息,经过分析用户和商品数据库级别没有任何关系,用户和商品需要建立关系,要通过订单,订单明细建立关系.根据这个需求,可以分析出需要查询的主表为: 查询主表:用户表 查询关联表:由于商品和用户没有关系,通过订单和订单明细进行关联,所以得出关联表是:orders订单表,orderDetail订单明细表,items商品表.这样的话,sql该如何去写?这样写: select orders.*, t_user.id user_id

基于MyBatis XML配置方法(全面了解)

MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息. 文档的顶层结构如下: configuration 配置 properties 属性 settings 设置 typeAliases 类型命名 typeHandlers 类型处理器 objectFactory 对象工厂 plugins 插件 environments 环境 environment 环境变量 transactionManager 事务管理器 dataSourc

基于MyBatis的简单使用(推荐)

MyBatis MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录. 搭建MyBatis 第一步:先创建一个项目,平常的Java project就行,项目结构先看看 第二步:导入相关的jar包(可

基于mybatis逆向工程的使用步骤详解

使用mybatis生成逆向工程的详细步骤,我个人感觉这个是最简单的一个了,虽然网上有很多种的方法来生成逆向工程,可是这个方法最简单.在这里我是使用maven搭建的环境,但是在正常的环境下也是一样的. 步骤: 1.创建一个genreatorConfig.xml文件,这个文件的名字可以任意.我创建的时候是将它放在了src/main/resources下,这个文件的内容并不需要去记,只需要去网上找就可以了.我们要做的只是对配置文件当中的一些部分做修改,修改成自己的数据就可以了. <?xml versi

springboot基于Mybatis mysql实现读写分离

近日工作任务较轻,有空学习学习技术,遂来研究如果实现读写分离.这里用博客记录下过程,一方面可备日后查看,同时也能分享给大家(网上的资料真的大都是抄来抄去,,还不带格式的,看的真心难受). 完整代码:https://github.com/FleyX/demo-project/tree/master/dxfl 1.背景 一个项目中数据库最基础同时也是最主流的是单机数据库,读写都在一个库中.当用户逐渐增多,单机数据库无法满足性能要求时,就会进行读写分离改造(适用于读多写少),写操作一个库,读操作多个库

基于Mybatis plus 自动代码生成器的实现代码

1.使用的是maven项目,添加依赖 <!-- mybatis-plus begin --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.2.0</version> </dependency> 还有数据库的连接 <dependency> <

Spring Boot整合Mybatis并完成CRUD操作的实现示例

MyBatis 是一款优秀的持久层框架,被各大互联网公司使用,本文使用Spring Boot整合Mybatis,并完成CRUD操作. 为什么要使用Mybatis?我们需要掌握Mybatis吗? 说的官方一点: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordina

详解java基于MyBatis使用示例

MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis.MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)

Spring boot2基于Mybatis实现多表关联查询

模拟业务关系: 一个用户user有对应的一个公司company,每个用户有多个账户account. spring boot 2的环境搭建见上文:spring boot 2整合mybatis 一.mysql创表和模拟数据sql CREATE TABLE IF NOT EXISTS `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `company_id` int(11) NOT NULL, PRI

基于mybatis batch实现批量提交大量数据

很多人在用 MyBatis 或者 通用 Mapper 时,经常会问有没有批量插入和批量更新的方法. 实际上许多时候没必要用 <foreach> 去实现特别复杂的批量操作.直接通过 MyBatis 的 BATCH 方式执行增删改方法即可. 下面是一个批量用法的例子: 在xml文件配置多条参数同时插入: <insert id="insertBatch2" parameterType="ctas.entity.SharkFlt"> <sele