MyBatisPlus系列第七篇:自定义全局操作-SQL自动注入器

一、SQL自动注入器AutoSqlInjector

根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自定义 Mybatisplus 自动注入的方法。

之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境时就注入。

1、在 Mapper 接口中定义相关的 CRUD 方法

public interface EmployeeMapper extends BaseMapper<Employee> {

    int deleteAll();

}

2、扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL

package com.ming.mp.injector;

import com.baomidou.mybatisplus.entity.TableInfo;
import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;

/**
 * 自定义全局 sql注入操作
 */
public class MySqlInject extends AutoSqlInjector {

    @Override
    public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
        super.inject(configuration, builderAssistant, mapperClass, modelClass, table);
        //Mapper接口中定义的方法deleteAll()处理成MappedStatement对象、加入到configuration中

        //1.注入SQL语句
        String sql = "delete from " +table.getTableName();

        //2.注入的方法名  与mapper接口中的方法名一致
        String sqlMethod = "deleteAll";

        //3.构建sqlSource对象
        SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql,modelClass);

        //4.构建删除的MappedStatement对象
        this.addDeleteMappedStatement(mapperClass,sqlMethod,sqlSource);

    }
}

3、在MP全局策略中、配置自定义注入器

    <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- 全局的主键策略 -->
        <property name="idType" value="0"></property>

        <!-- 全局的表前缀策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>

        <!--注入自定义的全局操作-->
        <property name="sqlInjector" ref="mySqlInject"/>


    </bean>

    <!--自定义SQL注入器-->
    <bean id="mySqlInject" class="com.ming.mp.injector.MySqlInject"/>

测试:

    private ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    private EmployeeMapper employeeMapper = context.getBean("employeeMapper",EmployeeMapper.class);

    @Test
    public void testSqlInjector(){
        int i = employeeMapper.deleteAll();
        System.out.println(i);
    }

报错:

Caused by: com.baomidou.mybatisplus.exceptions.MybatisPlusException: com.baomidou.mybatisplus.exceptions.MybatisPlusException: Error: Full table operation is prohibited. SQL: delete from tbl_employee
	at com.baomidou.mybatisplus.plugins.SqlExplainInterceptor.sqlExplain(SqlExplainInterceptor.java:131)
	at com.baomidou.mybatisplus.plugins.SqlExplainInterceptor.intercept(SqlExplainInterceptor.java:86)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
	at com.sun.proxy.$Proxy19.update(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
	at com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor.intercept(OptimisticLockerInterceptor.java:71)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
	at com.sun.proxy.$Proxy19.update(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
	at com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor.intercept(OptimisticLockerInterceptor.java:71)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
	at com.sun.proxy.$Proxy19.update(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
	... 34 more

报错原因:因为使用了注册执行分析插件,将他注释掉

	<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
		<!--作用就是我发现了当前你的操作是全表删除或更新、会阻止你的操作-->
		<property name="stopProceed" value="true"/>
	</bean>

MP启动的时候会加载MappedStatement

DEBUG  06-08 22:58:57,285 addMappedStatement: com.ming.mp.mapper.EmployeeMapper.deleteAll (MybatisConfiguration.java:67) 

二、自定义注入器的应用之逻辑删除

假删除、逻辑删除:并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据中的一个逻辑删除字段置为删除状态
update tbl_user set logic_flag = 1 → -1
步骤:

1、com.baomidou.mybatisplus.mapper.LogicSqlInjector

    <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- 全局的主键策略 -->
        <property name="idType" value="0"></property>

        <!-- 全局的表前缀策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>

        <!--注入自定义的全局操作-->
        <!--  <property name="sqlInjector" ref="mySqlInject"/>-->

        <!--注入逻辑删除-->
        <property name="sqlInjector" ref="logicSqlInjector"/>
    </bean>
    <!--逻辑删除-->
    <bean id="logicSqlInjector" class="com.baomidou.mybatisplus.mapper.LogicSqlInjector"/>

    <!--自定义SQL注入器-->
    <bean id="mySqlInject" class="com.ming.mp.injector.MySqlInject"/>

2、logicDeleteValue 逻辑删除全局值

<!-- 逻辑删除全局值为-1-->
<property name="logicDeleteValue" value="-1"></property>

3、logicNotDeleteValue 逻辑未删除全局值

    <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- 全局的主键策略 -->
        <property name="idType" value="0"></property>

        <!-- 全局的表前缀策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>

        <!--注入SQL自定义的全局操作-->
        <!--  <property name="sqlInjector" ref="mySqlInject"/>-->

        <!--注入逻辑删除-->
        <property name="sqlInjector" ref="logicSqlInjector"/>

        <!--注入逻辑删除的全局值-->
        <!-- 逻辑删除全局值为-1就是删除状态-->
        <property name="logicDeleteValue" value="-1"></property>
        <!--逻辑未删除全局值为1未删除状态-->
        <property name="logicNotDeleteValue " value="1"></property>
    </bean>

4、在 POJO 的逻辑删除字段 添加 @TableLogic 注解

public class User {
    private Integer id;

    private String name;

    @TableLogic
    private Integer logicFlag;//逻辑删除属性
}

5、会在 mp 自带查询和更新方法的 sql 后面,追加[逻辑删除字段]=[LogicNotDeleteValue默认值]
删除方法: deleteById()和其他 delete 方法, 底层 SQL 调用的是 update tbl_XXX set [逻辑删除字段] =[LogicNotDeleteValue默认值]

逻辑删除测试

    @Test
    public void testLogicDelete(){
        int i = userMapper.deleteById(1);
        System.out.println(i);
    }
DEBUG  06-08    23:52:15,864 ==>  Preparing: UPDATE tbl_user SET logic_flag=-1 WHERE id=?  (BaseJdbcLogger.java:159) 
DEBUG  06-08     23:52:15,884 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG  06-08     23:52:15,886 <==    Updates: 1 (BaseJdbcLogger.java:159) 
 Time6 ms - ID:com.ming.mp.mapper.UserMapper.deleteById
 Execute SQL:
    UPDATE
        tbl_user 
    SET
        logic_flag=-1 
    WHERE
        id=1]

DEBUG  06-08   23:52:15,890 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@769a1df5] (SqlSessionUtils.java:191) 
DEBUG  06-08   23:52:15,890 Returning JDBC Connection to DataSource (DataSourceUtils.java:327) 
1

逻辑删除后–查询测试查询不到结果的

    @Test
    public void testLogicDelete(){
//        int i = userMapper.deleteById(1);
//        System.out.println(i);
        User user = userMapper.selectById(1);
        System.out.println(user);
    }


DEBUG  06-08             23:58:59,350 ==>  Preparing: SELECT id,`name`,logic_flag AS logicFlag FROM tbl_user WHERE id=? AND logic_flag=1  (BaseJdbcLogger.java:159) 
DEBUG  06-08             23:58:59,370 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG  06-08             23:58:59,378 <==      Total: 0 (BaseJdbcLogger.java:159) 
 Time11 ms - ID:com.ming.mp.mapper.UserMapper.selectById
 Execute SQL:
    SELECT
        id,
        `name`,
        logic_flag AS logicFlag 
    FROM
        tbl_user 
    WHERE
        id=1 
        AND logic_flag=1]

DEBUG  06-08             23:58:59,381 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@769a1df5] (SqlSessionUtils.java:191) 
DEBUG  06-08             23:58:59,381 Returning JDBC Connection to DataSource (DataSourceUtils.java:327) 
null

三、公共字段填充

1、实现元对象处理器接口

com.baomidou.mybatisplus.core.handlers.MetaObjectHandler

公共字段填充:比如我们插入修改操作有一些字段没有提供值,我们希望有一些默认的值填充上去

  public abstract void insertFill(MetaObject metaObject);

  public abstract void updateFill(MetaObject metaObject);

MetaObject :元对象、它是mybatis提供的一个用于更加方便访问对象的属性、给对象的属性设置值的一个对象。还会用于包装我们的对象,支持object,mapper,collection对象等进行包装

本质上MetaObject 获取对象的属性值,或者给对象的属性设置值是要底层最终要通过rflector反射获取我们属性对应的方法的Invoker,最终Invoker.

2、开发步骤

1、注解填充字段注解填充字段 @TableField(… fill = FieldFill.INSERT) 查看FieldFill
有时候开发的时候不会提供该字段值,我们提供一个默认值,name为公共字段填充

public class User {
    private Integer id;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String name;
}

2、自定义公共字段填充处理器

package com.ming.mp.beans.metaobject;

import com.baomidou.mybatisplus.mapper.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;

/**
 * 自定义公共字段填充处理器
 */
public class MyMetaObject extends MetaObjectHandler {
    /**
     * 插入操作自动填充
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        //获取到需要被填充的字段值
        Object fieldValByName = getFieldValByName("name", metaObject);
        if (fieldValByName == null) {
            System.out.println("*********插入操作,满足填充条件**********");
            setFieldValByName("name","公共字段填充的名字",metaObject);
        }

    }

    /**
     * 修改操作自动填充
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        //获取到需要被填充的字段值
        Object fieldValByName = getFieldValByName("name", metaObject);
        if (fieldValByName == null) {
            System.out.println("*********修改操作,满足填充条件**********");
            setFieldValByName("name","公共字段填充的名字",metaObject);
        }
    }
}

3、MP全局注入 自定义公共字段填充处理器

    <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- 全局的主键策略 -->
        <property name="idType" value="0"></property>

        <!-- 全局的表前缀策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>

        <!--注入自定义的全局操作-->
        <!--  <property name="sqlInjector" ref="mySqlInject"/>-->

        <!--注入逻辑删除-->
        <property name="sqlInjector" ref="logicSqlInjector"/>

        <!--注入逻辑删除的全局值-->
        <!-- 逻辑删除全局值为-1就是删除状态-->
        <property name="logicDeleteValue" value="-1"></property>
        <!--逻辑未删除全局值为1未删除状态-->
        <property name="logicNotDeleteValue" value="1"></property>

        <!--注入自定义公共字段填充处理器-->
        <property name="metaObjectHandler" ref="myMetaObject"/>
    </bean>

    <!--自定义公共字段填充处理器-->
    <bean id="myMetaObject" class="com.ming.mp.beans.metaobject.MyMetaObject"/>

测试:插入的name字段是我们定义的公共字段填充的值、

    @Test
    public void testMetaObjectHandler() {
        User user = new User();
        user.setLogicFlag(1);
        userMapper.insert(user);
    }
DEBUG  06-09             22:45:09,072 Fetching JDBC Connection from DataSource (DataSourceUtils.java:110) 
DEBUG  06-09             22:45:09,072 JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ca18a14 [wrapping: com.mysql.jdbc.JDBC4Connection@c667f46]] will not be managed by Spring (SpringManagedTransaction.java:87) 
DEBUG  06-09             22:45:09,076 ==>  Preparing: INSERT INTO tbl_user ( `name`, logic_flag ) VALUES ( ?, ? )  (BaseJdbcLogger.java:159) 
DEBUG  06-09             22:45:09,097 ==> Parameters: 公共字段填充的名字(String), 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG  06-09             22:45:09,100 <==    Updates: 1 (BaseJdbcLogger.java:159) 
 Time8 ms - ID:com.ming.mp.mapper.UserMapper.insert
 Execute SQL:
    INSERT 
    INTO
        tbl_user
        ( `name`, logic_flag ) 
    VALUES ( '公共字段填充的名字', 1 )]
        

四、oracle主键Sequence(序列)

mysql支持注解自增、oracle不支持主键自增、Sequence序列去做主键自增

     <!--oracle驱动:因为oracle授权问题,不能从Maven仓库中下载到Oracle驱动-->
      <dependency>
          <groupId>com.oracle</groupId>
          <artifactId>ojdbc14</artifactId>
          <version>10.2.0.4.0</version>
      </dependency>

在这里插入图片描述

1、实体类配置主键Sequence、 @KeySequence(value = “序列名”,clazz = Integer.class 主键属性类型)

//Oracle主键自增
@KeySequence(value = "seq_user",clazz = Integer.class)
public class User {
    private Integer id;
 }

2、全局MP主键生成策略为IdType.INPUT

实体类主键上配置

@KeySequence(value = "序列名",clazz = Integer.class)
public class User {
    @TableId(type = IdType.INPUT)
    private Integer id;
 }

racle全局的主键策略

    <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- oracle全局的主键策略 -->
        <property name="idType" value="1"></property>

3、全局MP中配置oracle注解Sequence com.baomidou.mybatisplus.incrementer.OracleKeyGenerator

    <!--配置oracle主键sequence-->
    <bean id="oracleKeyGenerator" class="com.baomidou.mybatisplus.incrementer.OracleKeyGenerator"/>
 <!-- 定义MybatisPlus的全局策略配置-->
    <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
        <property name="dbColumnUnderline" value="true"></property>

        <!-- 全局的主键策略 -->
        <property name="idType" value="0"></property>


        <!-- 全局的表前缀策略配置 -->
        <property name="tablePrefix" value="tbl_"></property>

        <!--注入自定义的全局操作-->
        <!--  <property name="sqlInjector" ref="mySqlInject"/>-->

        <!--注入逻辑删除-->
        <property name="sqlInjector" ref="logicSqlInjector"/>

        <!--注入逻辑删除的全局值-->
        <!-- 逻辑删除全局值为-1就是删除状态-->
        <property name="logicDeleteValue" value="-1"></property>
        <!--逻辑未删除全局值为1未删除状态-->
        <property name="logicNotDeleteValue" value="1"></property>

        <!--注入自定义公共字段填充处理器-->
        <property name="metaObjectHandler" ref="myMetaObject"/>

        <!--oracle主键生成策略配置-->
        <property name="keyGenerator" ref="oracleKeyGenerator"/>
    </bean>

4、可以将@KeySequence定义在父类中、可实现多个子类对应的多个表公用一个Sequence

多个实体类公用一个序列实现主键自增

@KeySequence(value = "seq_user",clazz = Integer.class)
public abstract class Parent {
}

//Oracle主键自增
//@KeySequence(value = "序列名",clazz = Integer.class)
public class User extends parent{
    //@TableId(type = IdType.INPUT)
    private Integer id;
}

五、idea的快速开发插件

Mybatisx辅助idea快速开发
可以实现java与xml跳转、根据mapper中的方法自动生成xml结构
在线安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。
jar安装: File -> Settings -> Plugins ->install plugins from disk…选中mybatisx.jar安装

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Mybatis-Plus 是一个基于 Mybatis 的增强工具,它简化了 Mybatis 的开发流程,提供了很多实用的功能,其中之一就是代码生成。代码生成可以根据数据库表结构自动生成实体类、mapper 接口、xml 文件等代码,极大地提高了开发效率。但是,Mybatis-Plus 自动生成的实体类并不一定满足我们的需求,因此我们需要自定义模板来生成我们需要的类。 下面,我将介绍如何使用 Mybatis-Plus 自定义模板生成 dto、vo、convertor。 1. 创建自定义模板 我们需要在 Mybatis-Plus 的代码生成中创建自定义模板。打开 Mybatis-Plus 的代码生成,点击“自定义模板”选项卡,然后点击“添加模板”按钮,输入模板名称和文件名,然后点击“保存”按钮。 在模板编辑中,我们可以使用 FreeMarker 语法来编写模板。下面是一个简单的模板示例,用于生成 dto 类: ``` package ${dtoPackage}; import lombok.Data; @Data public class ${dtoName} { <#list table.columnList as column> private ${column.javaType} ${column.propertyName}; </#list> } ``` 在这个模板中,我们使用 `${}` 占位符来引用变量。`dtoPackage` 和 `dtoName` 变量由代码生成自动提供,表示生成的 dto 类的包名和类名。`table` 变量表示当前生成的表信息,包含表名、列名、列类型等信息。我们使用 `<#list>` 和 `</#list>` 标签来遍历表的列信息,并生成对应的属性。 2. 配置代码生成 在使用自定义模板之前,我们需要配置代码生成。打开 Mybatis-Plus 的代码生成,点击“全局配置”选项卡,在“自定义配置”中添加以下配置: ``` # dto 模板配置 dto=templates/dto.java.vm dtoOutputDir=src/main/java/${dtoPackage}/ ``` 其中,`dto` 是我们自定义模板的名称,`dtoOutputDir` 是生成的 dto 类的输出目录。我们还可以添加其他自定义模板和输出目录,例如: ``` # vo 模板配置 vo=templates/vo.java.vm voOutputDir=src/main/java/${voPackage}/ # convertor 模板配置 convertor=templates/convertor.java.vm convertorOutputDir=src/main/java/${convertorPackage}/ ``` 3. 生成代码 配置完成后,我们可以点击“执行”按钮来生成代码。代码生成将根据配置生成实体类、mapper 接口、xml 文件、dto、vo、convertor 等代码。我们只需要将生成的代码复制到项目中即可。 总结 使用 Mybatis-Plus 的代码生成可以大大提高开发效率,而自定义模板则可以生成我们需要的类。通过自定义模板,我们可以生成 dto、vo、convertor 等常用类,避免手写重复的代码,提高开发效率和代码质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值