程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

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

发布于2021-06-12 14:23     阅读(436)     评论(0)     点赞(17)     收藏(5)


一、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 )]
        

原文链接:https://blog.csdn.net/qq_29445811/article/details/117716281



所属网站分类: 技术文章 > 博客

作者:天花灯

链接:http://www.javaheidong.com/blog/article/222335/8b065840030c10064dac/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

17 0
收藏该文
已收藏

评论内容:(最多支持255个字符)