Mybatis-plus

目录

1、ActiveRecord

1.1、开启AR之旅

1.2、根据主键查询

1.3、新增数据

1.4、更新操作

1.5、删除操作

1.6、根据条件查询

2、Oracle 主键Sequence

3、插件

3.1、mybatis的插件机制

3.2、执行分析插件

3.3、性能分析插件

3.4、乐观锁插件

3.4.1、主要适用场景

3.4.2、插件配置

3.4.3、注解实体字段

3.4.4、测试

3.4.5、特别说明

4、Sql 注入器

4.1、编写MyBaseMapper

4.2、编写MySqlInjector

4.3、编写FindAll

4.4、注册到Spring容器

4.5、测试

5、自动填充功能

5.1、添加@TableField注解

5.2、编写MyMetaObjectHandler

5.3、测试

6、 逻辑删除

6.1、修改表结构

6.2、配置

6.3、测试

7、 通用枚举

7.1、修改表结构

7.2、定义枚举

7.3、配置

7.4、修改实体

7.5、测试

8、代码生成器

 8.1、创建工程

8.2、代码

8.3、测试

 9、MybatisX 快速开发插件


1ActiveRecord

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 即可。
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User extends Model<User> {

    @TableId(type = IdType.AUTO)
    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、根据主键查询

    @Test
    public void testSelectById(){
        User user = new User();
        user.setId(16L);

        User user1 = user.selectById();
        System.out.println(user1);
    }

1.3、新增数据

    @Test
    public void testInsert(){
        User user = new User();
        user.setUserName("diaochan");
        user.setPassword("123456");
        user.setAge(20);
        user.setName("貂蝉");
        user.setMail("diaochan@itcast.cn");
        user.setVersion(1);
        user.setSex(SexEnum.WOMAN); //使用的是枚举

        // 调用AR的insert方法进行插入数据
        boolean insert = user.insert();
        System.out.println("result => " + insert);
    }

1.4、更新操作

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(13L);// 查询条件
        user.setAge(31); // 更新的数据

        boolean result = user.updateById();
        System.out.println("result => " + result);
    }

1.5、删除操作

    @Test
    public void testDelete(){
        User user = new User();
        user.setId(13L);

        boolean delete = user.deleteById();
        System.out.println("result => " + delete);
    }

1.6、根据条件查询

    @Test
    public void testSelect(){
        User user = new User();

        QueryWrapper<User> wrapper  = new QueryWrapper<>();
        wrapper.ge("age", 30); //大于等于30岁的用户查询出来

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

2Oracle 主键Sequence

3、插件

3.1mybatis的插件机制

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下, MyBatis 允许使用插件来拦截的方法调用包括:
  • 1. Executor (update, query, flflushStatements, commit, rollback, getTransaction, close, isClosed)
  • 2. ParameterHandler (getParameterObject, setParameters)
  • 3. ResultSetHandler (handleResultSets, handleOutputParameters)
  • 4. StatementHandler (prepare, parameterize, batch, update, query)
我们看到了可以拦截 Executor 接口的部分方法,比如 update query commit rollback 等方法,还有其他接口的一些方法等。总体概括为:
  • 1. 拦截执行器的方法
  • 2. 拦截参数的处理
  • 3. 拦截结果集的处理
  • 4. 拦截Sql语法构建的处理

代码演示:

@Intercepts({@Signature(
        type= Executor.class,
        method = "update",
        args = {MappedStatement.class,Object.class})})
public class MyInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //拦截方法,具体业务逻辑编写的位置
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        //创建target对象的代理对象,目的是将当前拦截器加入到该对象中
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        //属性设置
    }
}
注入到 Spring 容器:
    @Bean //注入自定义的拦截器(插件)
    public MyInterceptor myInterceptor(){
        return new MyInterceptor();
    }
或者通过 xml 配置, mybatis-confifig.xml
<plugins>
        <!--配置拦截器-->
        <plugin interceptor="cn.itcast.mp.plugins.MyInterceptor"/>
    </plugins>

3.2、执行分析插件

MP 中提供了对 SQL执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境。当执行全表更新时,会抛出异常,这样有效防止了一些误操作。
SpringBoot 配置:
    @Bean //SQL分析插件
    public SqlExplainInterceptor sqlExplainInterceptor(){

        SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();

        List<ISqlParser> list = new ArrayList<>();
        list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器

        sqlExplainInterceptor.setSqlParserList(list);

        return sqlExplainInterceptor;
    }

3.3、性能分析插件

性能分析拦截器,用于输出每条 SQL 语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。
该插件只用于开发环境,不建议生产环境使用。
    <plugins>
        <!-- 性能分析插件 -->
        <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
            <!--最大的执行时间,单位为毫秒-->
            <property name="maxTime" value="100"/>
            <!--对输出的SQL做格式化,默认为false-->
            <property name="format" value="true"/>
        </plugin>
    </plugins>

3.4、乐观锁插件

3.4.1、主要适用场景

意图: 当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

3.4.2、插件配置

    <plugins>
        <!--乐观锁插件-->
        <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
    </plugins>

spring boot:

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

3.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;

3.4.4、测试

测试用例:
    /**
     * 测试乐观锁
     */
    @Test
    public void testUpdateVersion(){
        User user = new User();
        user.setId(2L);// 查询条件

        User userVersion = user.selectById();

        user.setAge(23); // 更新的数据
        user.setVersion(userVersion.getVersion()); // 当前的版本信息

        boolean result = user.updateById();
        System.out.println("result => " + result);
    }
执行日志:
  • 可以看到,更新的条件中有version条件,并且更新的version2
  • 如果再次执行,更新则不成功。这样就避免了多人同时更新时导致数据的不一致。

3.4.5、特别说明

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

4Sql 注入器

我们已经知道,在 MP 中,通过 AbstractSqlInjector BaseMapper 中的方法注入到了 Mybatis 容器,这样这些方法才可以正常执行。
那么,如果我们需要扩充 BaseMapper 中的方法,又该如何实现呢?

4.1、编写MyBaseMapper

public interface MyBaseMapper<T> extends BaseMapper<T> {

    List<T> findAll();

    // 扩展其他的方法

}
其他的 Mapper 都可以继承该 Mapper ,这样实现了统一的扩展。
public interface UserMapper extends MyBaseMapper<User> {

    User findById(Long id);
    
}

4.2、编写MySqlInjector

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

    @Override
    public List<AbstractMethod> getMethodList() {
        List<AbstractMethod> list = new ArrayList<>();

        // 获取父类中的集合
        list.addAll(super.getMethodList());

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

        return list;
    }
}

4.3、编写FindAll

public class FindAll extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {

        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql, modelClass);

        return this.addSelectMappedStatement(mapperClass, "findAll", sqlSource, modelClass, tableInfo);
    }
}

4.4、注册到Spring容器

    /**
     * 注入自定义的SQL注入器
     *
     * @return
     */
    @Bean
    public MySqlInjector mySqlInjector() {
        return new MySqlInjector();
    }

4.5、测试

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

5、自动填充功能

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

5.1、添加@TableField注解

    // 插入数据时进行填充
    //查询时不返回该字段的值
    @TableField(select = false, fill = FieldFill.INSERT) 
password 添加自动填充功能,在新增数据时有效。
FieldFill 提供了多种模式选择:
public enum FieldFill {

    //默认不填充
    DEFAULT,

    //插入时填充
    INSERT,

    //修改时填充
    UPDATE,

    //插入或者修改时填充
    INSERT_UPDATE;

    private FieldFill() {
    }
}

5.2、编写MyMetaObjectHandler

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
        * 插入数据时填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 先获取到password的值,再进行判断,如果为空,就进行填充,如果不为空,就不做处理
        Object password = getFieldValByName("password", metaObject);
        if(null == password){
           setFieldValByName("password", "888888", metaObject);
        }
    }

    /**
     * 更新数据时填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {

    }
}

5.3、测试

    @Test
    public void testInsert1() {
        User user = new User();
        user.setName("关羽");
        user.setUserName("guanyu");
        user.setAge(30);
        user.setVersion(1);
        int result = user.insert(user);
        System.out.println("result = " + result);
    }

6、 逻辑删除

开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE 操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。

6.1、修改表结构

tb_user 表增加 deleted 字段,用于表示数据是否被删除, 1 代表删除, 0 代表未删除。
ALTER TABLE `tb_user`
    ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;
同时,也修改 User 实体,增加 deleted 属性并且添加 @TableLogic 注解:
@TableLogic 
private Integer deleted;

6.2、配置

application.properties
#删除状态的值为:1
mybatis-plus.global-config.db-config.logic-delete-value=1
#未删除状态的值为:0
mybatis-plus.global-config.db-config.logic-not-delete-value=0

6.3、测试

@Test public void testDeleteById(){ 
    this.userMapper.deleteById(2L); 
}

执行的SQL

 可见,已经实现了逻辑删除。

7、 通用枚举

解决了繁琐的配置,让 mybatis 优雅的使用枚举属性!

7.1、修改表结构

ALTER TABLE `tb_user`
    ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;

7.2、定义枚举

public enum SexEnum implements IEnum<Integer> {
    
    MAN(1,"男"),
    WOMAN(2,"女");

    private int value;
    private String desc;

    SexEnum(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }

    @Override
    public String toString() {
        return this.desc;
    }
}

7.3、配置

#枚举包扫描
mybatis-plus.type-enums-package=cn.itcast.mp.enums

7.4、修改实体

private SexEnum sex;

7.5、测试

    @Test
    public void testInsert() {
        User user = new User();
        user.setName("貂蝉");
        user.setUserName("diaochan");
        user.setAge(20);
        user.setEmail("diaochan@itast.cn");
        user.setVersion(1);
        user.setSex(SexEnum.WOMAN);
        int result = this.userMapper.insert(user);
        System.out.println("result = " + result);
    }
SQL

查询:

    @Test
    public void testSelectById() {
        User user = this.userMapper.selectById(2L);
        System.out.println(user);
    }

结果:

 从测试可以看出,可以很方便的使用枚举了。

8、代码生成器

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

 8.1、创建工程

pom.xml
    <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>

8.2、代码

package cn.itcast.mp.generator;

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

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.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

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

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    /**
     * RUN THIS
     */
    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("awen");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

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

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("cn.awen.mp.generator");
        mpg.setPackageInfo(pc);

        // 自定义配置
        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 + "/itcast-mp-generator/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));

        // 策略配置
        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");
        strategy.setEntityLombokModel(true);
//        strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
        strategy.setInclude(scanner("表名"));
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

8.3、测试

代码已生成:

 9MybatisX 快速开发插件

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA ,进入 File -> Settings -> Plugins -> Browse Repositories ,输入 mybatisx 搜索并安装。
功能:
  • Java XML 调回跳转
  • Mapper 方法自动生成 XML

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值