首页 > 技术文章 > MyBatis Plus实战(一)

leejk 2021-07-19 09:45 原文

MyBatisPlus简介

MP官方介绍:https://mp.baomidou.com/

MP是MyBatis的增强版,在MyBatis基础之上扩充了其他功能,旨在简化开发、提高效率。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

MyBatisPlus实战

SpringBoot项目整合MP

  1. 在IDEA中下载mybatisx插件。

  2. 在pom.xml中引入MP的依赖

       <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>Latest Version</version>
        </dependency>
    
  3. dao层接口继承 Baseapper 类

    BaseMapper是MP封装好的类,里面定义了常用的CRUD方法。

  4. 在启动类添加 @MapperScan("mapper") 注解,扫描Mapper类

通过以上简单的配置,可以使用MP实现简单的CRUD操作,省去了Mapper.xml映射文件

实现CRUD操作

在控制台打印Sql语句

  1. 单数据源

    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  2. 多数据源

    public class MybatisPlusConfig{
    	@Bean("sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            // 导入mybatissqlsession配置
            MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
            // 指明数据源
            sessionFactory.setDataSource(multipleDataSource(dataSource0(), dataSource1(), dataSource2()));
            // 指明mapper.xml位置(配置文件中指明的xml位置会失效用此方式代替,具体原因未知)
            sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/**Mapper.xml"));
            // 指明实体扫描(多个package用逗号或者分号分隔)
            sessionFactory.setTypeAliasesPackage("gsa.geographic.system.entity");
            // 导入mybatis配置
            MybatisConfiguration configuration = new MybatisConfiguration();
            configuration.setJdbcTypeForNull(JdbcType.NULL);
            configuration.setMapUnderscoreToCamelCase(true);
            configuration.setCacheEnabled(false);
            // 配置打印sql语句
            configuration.setLogImpl(StdOutImpl.class);
            sessionFactory.setConfiguration(configuration);
            // 添加分页功能
            sessionFactory.setPlugins(new Interceptor[]{
                    paginationInterceptor()
            });
            // 导入全局配置
            sessionFactory.setGlobalConfig(globalConfiguration());
            return sessionFactory.getObject();
        }
    }
    

CRUD操作

在Spring Boot项目中配置好MP后,就可以进行简单的CRUD操作了。

BaseMapper类

提供了通用的CRUD方法,如下:

int insert(T entity);//插入一条记录

int deleteById(Serializable id);//根据ID删除

int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);//根据columnMap条件,删除记录

int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);//根据entity条件,删除记录

int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);//删除(根据ID批量删除)

int updateById(@Param(Constants.ENTITY) T entity);//根据ID修改

int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);//根据whereEntity条件,更新记录

T selectById(Serializable id);//根据ID查询

List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);//查询(根据ID批量查询)

List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);//查询(根据columnMap条件)

T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据entity条件,查询一条记录

Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据 Wrapper条件,查询总记录数

List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据 entity 条件,查询全部记录

List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据Wrapper条件,查询全部记录

List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据Wrapper条件,查询全部记录

IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据entity条件,查询全部记录(并翻页)

IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);//根据Wrapper 条件,查询全部记录(并翻页)

如何使用?让项目中的Mapper接口继承BaseMapper即可。

public interface UserMapper extends BaseMapper<User> {

}

常用注解

@TableName

一般情况下,实体名和数据库表名是根据驼峰命名规则相对应的,如SysUser类对应sys_user表。如果我们需要修改表名或类名,此时根据规则对应失效,MP提供了@TableName注解,我们直接可以修改实体类和数据库表的对应关系。

@TableName(value = "t_user")
public class User

@TableId

插入数据时,如果我们不指定主键Id的值,MP会为我们自动填充主键Id,仅在实体类中主键名为id下才有效。如果我们想定义的主键为userId,@TableId可以指定实体类中的主键。

@TableId
private Long userId;
//还可以对应列名
@Table(value = "id")
private Long userId;

@TableField

用在非主键字段,和@TableName相同,用在非主键字段上可以对应数据库字段名的值。

@TableField(value = "user_name")
private String name;

排除非表字段

实体类属性不存在于数据库表中,由于MP为属性和字段做了一一映射,所以如果存在非表字段的属性时会报错。

排除非表字段的三种方法

transient关键字

private transient String weChat;

定义为静态变量

private static String weChat;
//如果使用了lombok,它不会为静态变量创建getter和setter方法,所以我们需要手动创建。

@TableField的 exist 属性

@TableField(exist = false)
private String weChat;

插入

简单插入一条数据:

@Test
public void addTest() {

    User user = new User();
    user.setId(3L);
    user.setName("ez");
    user.setAge(20);
    user.setEmail("ezez@qq.com");
    user.setManagerId(1L);
    user.setCreateTime(LocalDateTime.now());
    userMapper.insert(user);
    
}

查询

通过Id查询:

    @Test
    public void selectById() {
        User user = userMapper.selectById(3L);
        System.out.println(user); //打印成功
    }

通过Id集合查询:

    @Test
    public void selectBatchIds() {
        //selectBatchIds方法传递的集合不能为null或empty
        List<User> userList = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
        userList.forEach(System.out::println);
    }

通过Map查询:

   @Test
    public void selectByMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("user_name", "mike");
	//  key代表的是数据库中的字段名,而不是实体属性名
        List<User> userList = userMapper.selectByMap(map);
	// 生成SQL:SELECT id,user_name AS name,age,email,manager_id,create_time,update_time,version,delete_id 
	// FROM t_user WHERE user_name = ?
        userList.forEach(System.out::println);
    }

更新

根据Id更新:

    @Test
    public void addTest() {
        User user = new User();
        user.setId(2L);
        user.setName("tom");
        user.setAge(15);
        user.setEmail("tomtom@qq.com");
        user.setManagerId(null);
        user.setCreateTime(LocalDateTime.now());

        userMapper.updateById(user);// 调用该方法,更新成功!

    }

使用UpdateWrapper的set方法:

    @Test
    public void updateByWrapper() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();

        updateWrapper.eq("user_name", "tom").set("age", 7);
        int rows = userMapper.update(null, updateWrapper);
        System.out.println(rows);
    }

LambdaUpdateWrapper:

  @Test
    public void UpdateByLambdaWrapper() {
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
        lambdaUpdateWrapper.eq(User::getName, "tom").set(User::getAge, 24);

        int rows = userMapper.update(null, lambdaUpdateWrapper);
        System.out.println(rows);
    }

推荐阅读