Mybatis-Plus知识点整理02

Mybatis-Plus 02

配置

MybatisPlus:

特性:

1.无侵入: 只做增强,不做改变,不会对现有工程产生影响

2.损耗小: 启动即会自动注入基本CURD,性能基本无损耗

3.强大的CURD操作,内置通用Mapper,通用Service,少量配置即可实现大部分的CURD操作,更有强大的条件构造器,满足各类需求

4.支持主键自动生成: 支持4种主键策略

5.内置分页插件:基于mybatis物理分页

6.内置代码生成器:采用代码或者Maven插件可以快速生成Mapper,Service,Model,Controller层代码

依赖:


        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.4.3.1</version>
        </dependency>

spring.xml 配置文件:

<!--spring整合mybatis-plus-->

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.sin.entity"/>
</bean>

实体类:

@Data//自动生成set/get等方法
@AllArgsConstructor//生成全参构造
@NoArgsConstructor//无参构造
@TableName("emp")//这个实体类对应的表
public class Emp {

    @TableId(type = IdType.AUTO)//操纵数据库主键自增
    private Integer empno;
    //员工姓名
    private String ename;
    //职位
    private String job;
    //领导
    private Integer mgr;
    //入职时间
    private Date hiredate;
    //工资
    private Double sal;
    //部门编号
    private Integer deptno;
    //奖金
    private Double comm;

}

mapper层:

public interface EmpMapper extends BaseMapper<Emp> {

}

service层:

public interface EmpService extends IService<Emp> {

}

serviceImpl实现类:

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class TestEmp {

    @Autowired
    private EmpService empService;
    
    @Test
    public void testGetAllEmpList(){
        List<Emp> list = empService.list();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }
}

补充:

1.classpath:target->classes下面的路径

2.bean:

1.所有的实体类

2.所有的java类

@Data 注解 //自动生成set/get等方法

依赖:

<!--get/set-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.0</version>
</dependency>

加在实体类上

@Data//自动生成set/get等方法
@AllArgsConstructor//生成全参构造
@NoArgsConstructor//无参构造

介绍

  • ActiveRecord
  • Mybatis-Plus的插件
  • Sql 注入器实现自定义全局操作
  • 自动填充功能
  • 逻辑删除
  • 代码生成器
  • MybatisX 快速开发插件

1、ActiveRecord

ActiveRecord(简称AR)一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于 ActiveRecord 往往只能感叹其优雅,所以我们也在 AR 道路上进行了一定的探索,希望大家能够喜欢。

什么是ActiveRecord?

ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。

ActiveRecord的主要思想是:

  • 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field;
  • ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;;
  • ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;

1.1、开启AR之旅

在MP中,开启AR非常简单,只需要将实体对象继承Model即可。

package com.test.pojo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 用户实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User extends Model<User> {

    //指定id类型为使用分布式ID生成器生成
    @TableId(type = IdType.ID_WORKER)
    private Long id;

    private String userName;

    //密码字段不应该被查询出来
    @TableField(select = false)
    private String password;

    private String name;
    private Integer age;

    //表中字段名和实体类属性名不一致
    @TableField(value = "email")
    private String mail;

    //表中不存在这个字段
    @TableField(exist = false)
    private String address;
}

1.2、根据主键查询

package com.test.test.ar;

import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * AR模式测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Test
    public void testAR() {
        User user = new User();
        user.setId(2L);
        User userResult = user.selectById();

        System.out.println(userResult);
    }
}

1.3、新增数据

package com.test.test.ar;

import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * AR模式测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Test
    public void testARInsert() {
        User user = new User();
        user.setName("混沌");
        user.setAge(30);
        user.setPassword("123456");
        user.setUserName("hundun");
        user.setMail("hundun@1000phone.com");

        boolean insert = user.insert();

        System.out.println(insert);
    }

}

1.4、更新操作

package com.test.test.ar;

import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * AR模式测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Test
    public void testARUpdate() {
        User user = new User();
        user.setId(4L);
        user.setAge(32);

        boolean update = user.updateById();
        System.out.println(update);
    }

}

1.5、删除操作

package com.test.test.ar;

import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * AR模式测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Test
    public void testARDelete() {
        User user = new User();
        user.setId(1352412605444091909L);

        boolean delete = user.deleteById();
        System.out.println(delete);
    }

}

1.6、根据条件查询

package com.test.test.ar;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.test.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * AR模式测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Test
    public void testARSelectList() {
        User user = new User();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.ge("age","20");

        List<User> users = user.selectList(userQueryWrapper);
        for (User user1 : users) {
            System.out.println(user1);
        }
    }

}

2、插件

2.4、乐观锁插件

2.4.1、主要适用场景

意图:

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
2.4.2、插件配置

spring xml:

<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>

spring boot启动类加入下面代码, 乐观锁配置 :

/**
 * 乐观锁插件
 */
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}
2.4.3、注解实体字段

需要为实体字段添加@Version注解。

  • 第一步,为表添加version字段,并且设置初始值为1:
ALTER TABLE `tb_user`
ADD COLUMN `version`  int(10) NULL AFTER `email`;

UPDATE `tb_user` SET `version`='1';
  • 第二步,为User实体对象添加version字段,并且添加@Version注解:
@Version
private Integer version;
2.4.4、测试

测试用例:

@Test
public void testUpdate(){
    User user = new User();
    user.setAge(30);
    user.setId(2L);
    user.setVersion(1); //获取到version为1

    int result = userMapper.updateById(user);
    System.out.println("result = " + result);
}

执行日志:

Preparing: UPDATE tb_user SET age=?, version=? WHERE id=? AND version=? 
Parameters: 30(Integer), 2(Integer), 2(Long), 1(Integer)
Updates: 1

可以看到,更新的条件中有version条件,并且更新的version为2。

如果再次执行,更新则不成功。这样就避免了多人同时更新时导致数据的不一致。

2.4.5、特别说明
  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity
  • 仅支持 updateById(id)update(entity, wrapper) 方法
  • 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!

3、Sql 注入器

我们已经知道,在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到了Mybatis容器,这样这些方法才可以正常执行。

那么,如果我们需要扩充BaseMapper中的方法,又该如何实现呢?

下面我们以扩展findAll方法为例进行学习。

3.1、编写MyBaseMapper

package com.test.mapper.base;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;

/**
 * 公共组件: 自定义公共Mapper, 所有业务Mapper都要继承这个接口
 */
public interface MyBaseMapper<T> extends BaseMapper<T> {

    /**
     * 查询表中所有数据方法
     */
    public List<T> findAll();
}

其他的Mapper都可以继承该Mapper,这样实现了统一的扩展。

如:

package com.test.mapper;

import com.test.mapper.base.MyBaseMapper;
import com.test.pojo.User;

/**
 * 用户Mapper
 */
public interface UserMapper extends MyBaseMapper<User> {

    public User findById(Long id);
}

3.2、编写MySqlInjector

如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector进行扩展。

package com.test.mapper.base;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;

import java.util.List;

/**
 * 公共组件: 自定义Sql注入器
 * 作用: 保证了原有BaseMapper中的所有方法可以使用, 
 *      并且加入了新的自定义公共方法可以使用
 */
public class MySqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList() {
        List<AbstractMethod> methodList = super.getMethodList();

        // 再扩充自定义的方法
        methodList.add(new FindAll());

        return methodList;
    }
}

3.3、编写FindAll

package com.test.mapper.base;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

/**
 * 公共组件: 自定义FindAll类, 查询表中所有数据
 */
public class FindAll extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sqlMethod = "findAll";
        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
    }
}

3.4、注册到Spring容器

/**
 * 公共组件: 自定义SQL注入器
 */
@Bean
public MySqlInjector mySqlInjector(){
    return new MySqlInjector();
}

3.5、测试

@Test
public void testFindAll(){
    List<User> users = userMapper.findAll();
    for (User user : users) {
        System.out.println(user);
    }
}

输出的SQL:

[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] ==>  Preparing: select * from tb_user 
[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] ==> Parameters: 
[main] [com.test.mapper.UserMapper.findAll]-[DEBUG] <==      Total: 7

至此,我们实现了全局扩展SQL注入器。

4、自动填充功能

有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version等。在MP中提供了这样的功能,可以实现自动填充。

4.1、添加@TableField注解

//插入数据时进行填充, 并且查询时不被查询出来
@TableField(select = false, fill = FieldFill.INSERT)
private String password;

为password添加自动填充功能,在新增数据时有效。

FieldFill提供了多种模式选择:

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入时填充字段
     */
    INSERT,
    /**
     * 更新时填充字段
     */
    UPDATE,
    /**
     * 插入和更新时填充字段
     */
    INSERT_UPDATE
}

4.2、编写MyMetaObjectHandler

package com.test.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

/**
 * 自定义: 字段自动填充处理器
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * insert语句, 如果字段为空自动填充处理方法
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        Object password = getFieldValByName("password", metaObject);
        if(null == password){
            //字段为空,可以进行填充
            setFieldValByName("password", "123456", metaObject);
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {

    }
}

4.3、测试

@Test
public void testInsertAuto(){
    User user = new User();
    user.setName("关羽");
    user.setUserName("guanyu");
    user.setAge(30);
    user.setMail("guanyu@1000phone.com");
    user.setVersion(1);

    int result = this.userMapper.insert(user);
    System.out.println("result = " + result);
}

6、代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f15WhC8x-1672022129401)(Pictures/generator.gif)]

6.1、创建工程

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>test_mybatis_plus_generator</artifactId>
    <version>1.0-SNAPSHOT</version>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <properties>
        <!-- 项目源码及编译输出的编码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 项目编译JDK版本 -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--mybatis-plus的springboot支持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

6.2、代码

package com.test;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * mysql 代码生成器演示例子
 */
public class MysqlGenerator {

    /**
     * 生成方法
     */
    public static void main(String[] args) {
        //1. 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        //2. 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        //3. 类上注释, 代码作者, 可以写自己名字
        gc.setAuthor("zhangsan");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        /**
         * 4. 数据源配置
         */
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://127.0.0.1:3306/test_mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);

        //5. 包配置
        PackageConfig pc = new PackageConfig();
        //6. 模块名字, 一定要按照, 用户模块, 订单模块等分模块
        pc.setModuleName("user");
        //7. 模块父级包名, 一般为组织名
        pc.setParent("com.test");
        mpg.setPackageInfo(pc);

        //8. 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        //9. 配置模板
        mpg.setTemplate(new TemplateConfig().setXml(null));

        /**
         * 10. 策略配置
         */
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        //strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");

        //11. 是否使用Lombok
        strategy.setEntityLombokModel(true);
        //12. controller是否为Rest形式
        strategy.setRestControllerStyle(true);

        //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");

        /**
         * 13. 如果 setInclude() 不加参数, 会自定查找所有表
         *     如需要制定单个表, 需填写参数如: strategyConfig.setInclude("user_info);
         */
        strategy.setInclude();

        //strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);

        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        System.out.println("===================== MyBatis Plus Generator ==================");

        mpg.execute();
    }
}

6.3. 代码生成器使用注意事项

  • 执行生成器如果有问题, 需要将生成后的内容删掉, 然后再执行生成代码, 从新生成.
  • 上面生成器项目创建的时候只能是project, 不能是model, 否则生成的文件有问题.

7、MybatisX 快速开发插件

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。

功能:

  • Java 与 XML 跳转
  • Mapper 方法自动生成 XML

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QQQ549ij-1672022129402)(Pictures/mybatisx-001.gif)]

     */
    strategy.setInclude();

    //strategy.setSuperEntityColumns("id");
    strategy.setControllerMappingHyphenStyle(true);

    strategy.setTablePrefix(pc.getModuleName() + "_");
    mpg.setStrategy(strategy);
    mpg.setTemplateEngine(new FreemarkerTemplateEngine());

    System.out.println("===================== MyBatis Plus Generator ==================");

    mpg.execute();
}

}




### 6.3. 代码生成器使用注意事项

- **执行生成器如果有问题, 需要将生成后的内容删掉, 然后再执行生成代码, 从新生成.**
- **上面生成器项目创建的时候只能是project, 不能是model, 否则生成的文件有问题.**

## 7、MybatisX 快速开发插件

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 `mybatisx` 搜索并安装。

功能:

- Java 与 XML 跳转
- Mapper 方法自动生成 XML 

[外链图片转存中...(img-QQQ549ij-1672022129402)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值