欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mybatisplus 的SQL攔截器實現(xiàn)關聯(lián)查詢功能

 更新時間:2021年06月04日 14:19:12   作者:_JenKin  
大家都知道m(xù)ybatisplus不支持關聯(lián)查詢,后來學習研究發(fā)現(xiàn)mybatisplus的SQL攔截器可以實現(xiàn)這一操作,下面小編給大家分享我的demo實現(xiàn)基本的關聯(lián)查詢功能沒有問題,對mybatisplus關聯(lián)查詢相關知識感興趣的朋友一起看看吧

由于項目中經(jīng)常會使用到一些簡單地關聯(lián)查詢,但是mybatisplus還不支持關聯(lián)查詢,不過在看官方文檔的時候發(fā)現(xiàn)了mybatisplus的SQL攔截器(其實也是mybatis的)就想著能不能在SQL執(zhí)行的時候做一些處理以至于可以支持關聯(lián)查詢,于是就動手開始了,目前還只是一個初步的demo,但是一些基本的關聯(lián)查詢功能經(jīng)過驗證是沒有問題的

環(huán)境信息

jdk: 1.8
springboot: 2.3.4.RELEASE
mybatisplus: 3.4.2
lombok:1.18.12

代碼設計

代碼涉及四個關鍵的類:

JoinBuilder
這是一個建造者類,主要適用于生成關聯(lián)查詢的語句

CaseBuilder
這也是一個建造者類,主要是用來生成連接查詢的條件語句

MyQueryWrapper
這是查詢器,這里繼承了官方的QueryWrapper,然后擴展了一些功能。添加了關聯(lián)查詢的功能

JoinQueryInterceptor
這是SQL攔截器,在上面使用自定義的查詢器添加了關聯(lián)查詢之后就可以使用SQL攔截器進行sql的構(gòu)造

類關系圖如下:

在這里插入圖片描述

代碼實現(xiàn)

實現(xiàn)連接條件構(gòu)造器

package com.jenkin.common.config;

import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;

import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;

/**
 * @author jenkin
 * @Since 2021年4月12日14:45:58
 * @Version 1.0
 * @Description : 關聯(lián)查詢join構(gòu)造器
 */
@Slf4j
public class JoinBuilder {
    private StringBuilder sb = new StringBuilder();
    /**
     * 關聯(lián)表里面的查詢字段,比如要查詢關聯(lián)的用戶表里面的用戶名稱
     */
    private String[] selectFields;
    /**
     * 關聯(lián)表
     */
    private String joinTable;

    /**
     * 查詢字段去重
     */
    Set<String> set = new HashSet<>();
    /**
     * 主表
     */
    private String mainTable;
    /**
     * 關聯(lián)類型
     */
    private String joinType;


    private static final String LEFT_BRACKET = " ( ";
    private static final String RIGHT_BRACKET = " ) ";
    private static final String AND = " AND ";
    private static final String OR = " OR ";
    /**
     * 左連接
     */
    public static final String LEFT = " left ";
    /**
     * 右連接
     */
    public static final String RIGHT = " right ";
    /**
     * 內(nèi)連接
     */
    public static final String INNER = " inner ";


    public JoinBuilder selectField(String... fields) {
        this.selectFields = fields;
        if (!ArrayUtil.isEmpty(this.selectFields)) {
            for (int i = 0; i < this.selectFields.length; i++) {
                this.selectFields[i] = StringUtils.camelToUnderline(this.selectFields[i]);
                set.add(this.selectFields[i].toUpperCase());
            }
        }
        return this;
    }


    public Set<String> getSelectFields() {
        return set;


    }


    public String getMainTable() {
        return mainTable;
    }

    public String getSubTable() {
        return this.joinTable;
    }


    /**
     * @param joinType  關聯(lián)類型  JoinBuilder.LEFT,JoinBuilder.RIGHT,JoinBuilder.INNER
     * @param mainTable 主表
     * @param joinTable 關聯(lián)表
     * @return
     */
    public JoinBuilder join(String joinType, String mainTable, String joinTable) {
        mainTable = StringUtils.camelToUnderline(mainTable);
        ;
        joinTable = StringUtils.camelToUnderline(joinTable);
        ;
        this.joinTable = joinTable;
        this.mainTable = mainTable;
        this.joinType = joinType;
        return this;
    }


    public static JoinBuilder build() {
        return new JoinBuilder();
    }

    public JoinBuilder and() {
        sb.append(AND);
        return this;
    }

    public JoinBuilder or() {
        sb.append(OR);
        return this;
    }

    public StringBuilder getSql() {
        return sb;
    }

    public JoinBuilder on(CaseBuilder builder) {
        sb.append(LEFT_BRACKET).append(builder.getSql()).append(RIGHT_BRACKET);
        return this;
    }

    public Join getJoin() {
        CCJSqlParserManager pm = new CCJSqlParserManager();
        String sql = "select * from " + mainTable + " " + joinType + " join " + joinTable + " on " + sb;
        try {
            net.sf.jsqlparser.statement.Statement parse = pm.parse(new StringReader(sql));
            if (parse instanceof Select) {
                return ((PlainSelect) ((Select) parse).getSelectBody()).getJoins().get(0);
            }
            return null;
        } catch (JSQLParserException e) {
            log.warn(sql);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author jenkin
     * @Since 2021年4月12日14:45:58
     * @Version 1.0
     * @Description : 條件構(gòu)造器,局限于關聯(lián)查詢
     */
    public static class CaseBuilder {


        /**
         * SQL語句
         */
        private StringBuilder sb = new StringBuilder();
        private static final String LEFT_BRACKET = " ( ";
        private static final String RIGHT_BRACKET = " ) ";


        private static final String EQ = "=";
        private static final String NE = "<>";
        private static final String GT = ">";
        private static final String LT = "<";
        private static final String GT_EQ = ">=";
        private static final String LT_EQ = "<=";
        private static final String AND = " AND ";
        private static final String OR = " OR ";


        public static CaseBuilder build() {
            return new CaseBuilder();
        }


        public StringBuilder getSql() {
            return sb;
        }


        /**
         * 把條件表達式用括號包裹起來
         *
         * @param builder
         * @return
         */
        public CaseBuilder brackets(CaseBuilder builder) {
            sb.append(LEFT_BRACKET).append(builder.sb).append(RIGHT_BRACKET);
            return this;
        }


        public CaseBuilder and() {
            sb.append(AND);
            return this;
        }

        public CaseBuilder or() {
            sb.append(OR);
            return this;
        }


        /**
         * 規(guī)定左側(cè)為主表的列
         * ,右側(cè)為從表的列,不可以寫反
         * 注意,在使用定值查詢的時候 例如 on a.name = b.name and age = 1
         * 這個時候一樣要遵循左邊為主表,右邊為關聯(lián)表的規(guī)則.
         * 例如
         * <p>
         * 1、 and里面的條件 age字段是存在在主表里面的 那么就寫成 eq("age",1)
         * 2、如果age字段是在關聯(lián)表里面的,那么應該寫成 eq(1,"age")
         * <p>
         * 其他的條件語句例如,ne,gt,lt等等也適用這個邏輯
         *
         * @param left  左側(cè)列名稱
         * @param right 右側(cè)列名稱
         * @return
         */
        public CaseBuilder eq(Object left, Object right) {
            if (left instanceof String) {
                left = StringUtils.camelToUnderline((String) left);
            }
            if (right instanceof String) {
                right = StringUtils.camelToUnderline(String.valueOf(right));
            }
            sb.append(left).append(EQ).append(right);
            return this;
        }

        /**
         * 規(guī)定左側(cè)為主表的列
         * ,右側(cè)為從表的列,不可以寫反
         *
         * @param left  左側(cè)列名稱
         * @param right 右側(cè)列名稱
         * @return
         */
        public CaseBuilder ne(String left, Object right) {
            left = StringUtils.camelToUnderline(left);
            if (right instanceof String) {
                right = StringUtils.camelToUnderline(String.valueOf(right));
            }
            sb.append(left).append(NE).append(right);
            return this;
        }

        /**
         * 關聯(lián)查詢一般是列關聯(lián),如果條件里面有值等式,要做特殊處理,目前還不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder gt(String left, Object right) {
            sb.append(left).append(GT).append(right);
            return this;
        }

        /**
         * 關聯(lián)查詢一般是列關聯(lián),如果條件里面有值等式,要做特殊處理,目前還不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder gtEq(String left, Object right) {
            sb.append(left).append(GT_EQ).append(right);
            return this;
        }

        /**
         * 關聯(lián)查詢一般是列關聯(lián),如果條件里面有值等式,要做特殊處理,目前還不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder lt(String left, Object right) {
            sb.append(left).append(LT).append(right);
            return this;
        }

        /**
         * 關聯(lián)查詢一般是列關聯(lián),如果條件里面有值等式,要做特殊處理,目前還不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder ltEq(String left, Object right) {
            sb.append(left).append(LT_EQ).append(right);
            return this;
        }
    }
}

定制化QueryWrapper

在這個定制化的查詢器里面添加了一個addJoin的方法用來添加關聯(lián)查詢

package com.jenkin.common.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jenkin.common.entity.qos.Sort;

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

/**
 * @author :jenkin
 * @date :Created at 2020/3/13 12:07
 * @description:條件構(gòu)造器,重寫字符串轉(zhuǎn)換方法
 * @modified By:
 * @version: 1.0
 */
public class
MyQueryWrapper<T> extends QueryWrapper<T> {
    /**
     * 關聯(lián)查詢構(gòu)造器
     */
    private final List<JoinBuilder> joinBuilder = new ArrayList<>();


    /**
     * 獲取 columnName
     *
     * @param column
     */
    @Override
    protected String columnToString(String column) {
        return StringUtils.camelToUnderline(column);
    }


    public static<T> MyQueryWrapper<T> query(){
        return new MyQueryWrapper<T>();
    }


    /**
     * 關聯(lián)查詢構(gòu)造
    * @param builder
     * @return
     */
    public  MyQueryWrapper<T> addJoin(JoinBuilder builder){
        this.joinBuilder.add(builder);
        return this;
    }

    public List<JoinBuilder> getJoinBuilder() {
        return joinBuilder;
    }
    /**
     * 排序
     * @param sorts
     * @return
     */
    public QueryWrapper<T> sort(List<Sort> sorts){
        if(!CollectionUtils.isEmpty(sorts)){
            sorts.forEach(item->{
                orderBy(item.getSortField()!=null,"asc".equals(item.getSortValue()),item.getSortField());
            });
        }
        return this;
    }

}

定義SQL攔截器

通過自定義的SQL攔截器去攔截我們寫好的關聯(lián)查詢,然后生成對應的SQL

package com.jenkin.common.config;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* @author jenkin
* @className JoinQueryInterceptor
* @description TODO
* @date 2021/4/12 14:58
*/
public class JoinQueryInterceptor extends JsqlParserSupport implements InnerInterceptor {
    /**
     * 保存我們的關聯(lián)查詢的上下文信息
     */
    static ThreadLocal<List<JoinBuilder>> joinBuilderThreadLocal = new ThreadLocal<>();
    
    /**
     * 操作前置處理
     * <p>
     * 改改sql啥的
     *
     * @param executor      Executor(可能是代理對象)
     * @param ms            MappedStatement
     * @param parameter     parameter
     * @param rowBounds     rowBounds
     * @param resultHandler resultHandler
     * @param boundSql      boundSql
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                            ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        if (parameter instanceof MapperMethod.ParamMap) {
            for (Object value : ((MapperMethod.ParamMap) parameter).values()) {
                if (value instanceof MyQueryWrapper) {
                    List<JoinBuilder> joinBuilders = ((MyQueryWrapper) value).getJoinBuilder();
                    if(!CollectionUtils.isEmpty(joinBuilders)){
                        joinBuilderThreadLocal.set(joinBuilders);
                        try {
                            logger.debug("開始添加關聯(lián)查詢SQL");
                            String s = this.parserSingle(boundSql.getSql(), parameter);
                            logger.debug("加了關聯(lián)查詢的SQL : "+ s);
                            PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
                            mpBs.sql(s);
                        }finally {
                            joinBuilderThreadLocal.remove();
                        }
                        return;
                    }
                }
            }
        }
    }
    
    /**
     * 查詢
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        List<JoinBuilder> joinBuilders = joinBuilderThreadLocal.get();
        PlainSelect selectBody = (PlainSelect) select.getSelectBody();
        if (selectBody.getFromItem().getAlias()==null) {
            selectBody.getFromItem().setAlias(new Alias("mainjointable"));
        }
        setJoins(selectBody,joinBuilders);


    }


    private void setJoins(PlainSelect selectBody,List<JoinBuilder> joinBuilders) {
        List<SelectItem> selectItems = selectBody.getSelectItems();
        Expression where = selectBody.getWhere();
        List<Join> joins = new ArrayList<>();
        for (int i = 0; i < joinBuilders.size(); i++) {
            JoinBuilder joinBuilder = joinBuilders.get(i);
            Join builderJoin = joinBuilder.getJoin();
            Set<String> selectFields = new HashSet<>(joinBuilder.getSelectFields());
            Join join = new Join();
            join.setLeft(builderJoin.isLeft());
            join.setRight(builderJoin.isRight());
            join.setInner(builderJoin.isInner());
            Table table = new Table(joinBuilder.getSubTable());
            table.setAlias( new Alias("subjointable"+i));
            setSelectItems(table,selectFields,selectItems,selectBody);
            join.setRightItem(table);
//            Expression expression = getOnExpressionWithTable(joinBuilder);
            Expression onExpression = joinBuilder.getJoin().getOnExpression();
            selectFields = new HashSet<>(joinBuilder.getSelectFields());
            setOnCase(onExpression,table,selectFields,(Table) selectBody.getFromItem(),false);
            join.setOnExpression(onExpression);
            joins.add(join);
            selectFields = new HashSet<>(joinBuilder.getSelectFields());
            setWhere(where,table,selectFields,(Table) selectBody.getFromItem());
        }
        selectBody.setJoins(joins);
    }


//    private Expression getOnExpressionWithTable(JoinBuilder joinBuilder) {
        setWhere(joinBuilder.getJoin().getOnExpression(),);
//        return joinBuilder.getJoin().getOnExpression();
//    }


    private void setSelectItems(Table table,  Set<String> selectFields, List<SelectItem> selectItems, PlainSelect selectBody) {


        for (SelectItem selectItem : selectItems) {
            if (selectItem instanceof SelectExpressionItem) {
                if (((SelectExpressionItem) selectItem).getExpression() instanceof Column && selectBody.getFromItem() instanceof Table) {
                    Column expression = (Column) ((SelectExpressionItem) selectItem).getExpression();
                    if (expression.getTable()==null&&selectFields.contains(expression.getColumnName().toUpperCase())){
                        expression.setTable(table);
                        selectFields.remove(expression.getColumnName().toUpperCase());
                    }else if(expression.getTable()==null){
                        expression.setTable((Table) selectBody.getFromItem());
                    }
                }
            }
        }
        if (!selectFields.isEmpty()){
            for (String selectField : selectFields) {
                SelectExpressionItem selectExpressionItem = new SelectExpressionItem();
                Column column = new Column();
                column.setTable(table);
                column.setColumnName(selectField);
                selectExpressionItem.setExpression(column);
                selectItems.add(selectExpressionItem);
            }
        }
    }
    
    /**
     *
     * @param on
     * @param subTable
     * @param joinSelectFields
     * @param sourceTable
     * @param isLeft 是否是左側(cè)列,如果是那么就是主表,如果false,那么就是關聯(lián)表,如果為null,那么就需要根據(jù)join字段判斷
     */
    private void setOnCase(Object on, Table subTable, Set<String> joinSelectFields , Table sourceTable,Boolean isLeft) {
        if (on==null) {
            return;
        }
        if (on instanceof Column) {
            Column column = (Column) on;
            if((column).getTable()==null &&isLeft!=null){
                (column).setTable(isLeft?sourceTable:subTable);
            }
            if (isLeft==null&&column.getTable()==null){
                (column).setTable(joinSelectFields.contains(column.getColumnName().toUpperCase())?subTable:sourceTable);
            }
        }else if (on instanceof BinaryExpression){
            setOnCase(((BinaryExpression) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,true);
            setOnCase(((BinaryExpression) on).getRightExpression(),subTable,joinSelectFields,sourceTable,false);
        }else if (on instanceof Parenthesis){
            setOnCase(((Parenthesis) on).getExpression(),subTable,joinSelectFields,sourceTable,false);
        }else if(on instanceof IsNullExpression){
            setOnCase(((IsNullExpression) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,null);
        }else if (on instanceof Between){
            setOnCase(((Between) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,null);
        }
        //有其他條件再補充
    }
    
    private void setWhere(Object where, Table subTable, Set<String> joinSelectFields , Table sourceTable) {
        if (where==null) {
            return;
        }
        if (where instanceof Column) {
            Column column = (Column) where;
            if((column).getTable()==null&&joinSelectFields.contains((column).getColumnName().toUpperCase())){
                (column).setTable(subTable);
            }else if((column).getTable()==null){
                (column).setTable(sourceTable);
            }
        }else if (where instanceof BinaryExpression){
            setWhere(((BinaryExpression) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
            setWhere(((BinaryExpression) where).getRightExpression(),subTable,joinSelectFields,sourceTable);
        }else if (where instanceof Parenthesis){
            setWhere(((Parenthesis) where).getExpression(),subTable,joinSelectFields,sourceTable);
        }else if(where instanceof IsNullExpression){
            setWhere(((IsNullExpression) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
        }else if(where instanceof Between){
            setWhere(((Between) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
        }
        //有其他條件再補充
    }
}

注入攔截器

緊接著只需要在mybatisplus的配置文件里面注入這個攔截器就可以了

在這里插入圖片描述

使用示例

使用的過程我們分為兩步:

添加字段到主表PO
如圖,紅框中的部分是我們添加的需要從其他表里面關聯(lián)查詢的字段,注意這些字段需要使用@TableField注解標注,并且 select字段和exist字段都要為false,不然會影響新增和修改操作

在這里插入圖片描述

queryWrapper構(gòu)造關聯(lián)查詢

把字段添加好之后就可以開始寫關聯(lián)查詢了,下奶的示例應該是一個涵蓋了大部分場景的示例了,多表關聯(lián),多條件關聯(lián),等等

 MyQueryWrapper<MenuPo> queryWrapper = new MyQueryWrapper<>();
        //添加一個關聯(lián)表查詢,關聯(lián)用戶表
        queryWrapper.addJoin(
                JoinBuilder.build()
                        //查詢用戶表里面的用戶名稱和用戶郵箱字段
                        .selectField(MenuPo.Fields.userName, MenuPo.Fields.userEmail)
                        //使用左連接關聯(lián)
                        .join(JoinBuilder.LEFT, MenuPo.class, UserPo.class)
                        //設置關聯(lián)條件
                        .on(JoinBuilder.CaseBuilder.build()
                                //主表的創(chuàng)建人字段等于關聯(lián)表的用戶編碼字段
                                // 注意,在條件中默認是第一個參數(shù)為主表的字段,第二個參數(shù)為關聯(lián)表的字段
                                .eq(BasePo.Fields.createdBy, UserPo.Fields.userCode)
                        )
        //再添加一個關聯(lián)查詢,關聯(lián)角色表
        ).addJoin(
                JoinBuilder.build()
                        //查血角色表里面的角色名稱
                        .selectField(MenuPo.Fields.roleName)
                        //左連接
                        .join(JoinBuilder.LEFT,MenuPo.class, RolePo.class)
                        //關聯(lián)條件
                        .on(JoinBuilder.CaseBuilder.build()
                                //code等于角色code
                            .eq(MenuPo.Fields.code, RolePo.Fields.roleCode)
                                //并且
                            .and()
                                //括號
                            .brackets(
                                    //parent =-1 or parent =1
                                    JoinBuilder.CaseBuilder.build()
                                            .eq(MenuPo.Fields.parent,-1)
                                            .or()
                                            .eq(MenuPo.Fields.parent,1)
                            )
                )
         //外層篩選條件,用戶名=jenkin       
        ).eq(MenuPo.Fields.userName,"jenkin");
        //執(zhí)行查詢
        menuService.list(queryWrapper);

可以在控制臺看到執(zhí)行的SQL:

SELECT
	mainjointable.id,
	mainjointable.NAME,
	mainjointable.CODE,
	mainjointable.parent,
	mainjointable.menu_level,
	mainjointable.permissions,
	mainjointable.menu_url,
	mainjointable.menu_icon,
	mainjointable.menu_order,
	mainjointable.menu_type,
	mainjointable.delete_flag,
	mainjointable.created_by,
	mainjointable.creation_date,
	mainjointable.last_update_date,
	mainjointable.last_updated_by,
	mainjointable.version_number,
	subjointable0.USER_EMAIL,
	subjointable0.USER_NAME,
	subjointable1.ROLE_NAME 
FROM
	lsc_menu AS mainjointable
	LEFT JOIN lsc_user AS subjointable0 ON ( mainjointable.created_by = subjointable0.user_code )
	LEFT JOIN lsc_role AS subjointable1 ON (
		mainjointable.CODE = subjointable1.role_code 
	AND ( mainjointable.parent = - 1 OR mainjointable.parent = 1 )
	) 
WHERE
	mainjointable.delete_flag = 0 
	AND (
	subjointable0.user_name = ?)

到此這篇關于基于mybatisplus 的SQL攔截器實現(xiàn)關聯(lián)查詢的文章就介紹到這了,更多相關mybatisplus關聯(lián)查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 排序算法圖解之Java歸并排序的實現(xiàn)

    排序算法圖解之Java歸并排序的實現(xiàn)

    歸并排序是建立在歸并操作上的一種有效,穩(wěn)定的排序算法,該算法是采用分治法(Divide?and?Conquer)的一個非常典型的應用。本文主要介紹了歸并排序的實現(xiàn),需要的可以參考一下
    2022-11-11
  • SpringBoot?整合mapstruct的實現(xiàn)步驟

    SpringBoot?整合mapstruct的實現(xiàn)步驟

    這篇文章主要介紹了SpringBoot整合mapstruct,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 分布式醫(yī)療掛號系統(tǒng)Nacos微服務Feign遠程調(diào)用數(shù)據(jù)字典

    分布式醫(yī)療掛號系統(tǒng)Nacos微服務Feign遠程調(diào)用數(shù)據(jù)字典

    這篇文章主要為大家介紹了分布式醫(yī)療掛號系統(tǒng)Nacos微服務Feign遠程調(diào)用數(shù)據(jù)字典,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2022-04-04
  • java實現(xiàn)IP地址轉(zhuǎn)換

    java實現(xiàn)IP地址轉(zhuǎn)換

    這篇文章主要為大家詳細介紹了java實現(xiàn)IP地址轉(zhuǎn)換,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • springboot2.X整合prometheus監(jiān)控的實例講解

    springboot2.X整合prometheus監(jiān)控的實例講解

    這篇文章主要介紹了springboot2.X整合prometheus監(jiān)控的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • SpringBoot集成ActiveMQ的實戰(zhàn)全過程

    SpringBoot集成ActiveMQ的實戰(zhàn)全過程

    消息隊列中間件是分布式系統(tǒng)中重要的組件,主要解決應用耦合、異步消息、流量削鋒等問題,實現(xiàn)高性能、高可用、可伸縮和最終一致性架構(gòu),是大型分布式系統(tǒng)不可缺少的中間件,這篇文章主要給大家介紹了關于SpringBoot集成ActiveMQ的相關資料,需要的朋友可以參考下
    2021-11-11
  • java數(shù)據(jù)結(jié)構(gòu)ArrayList詳解

    java數(shù)據(jù)結(jié)構(gòu)ArrayList詳解

    本文詳細講解了java數(shù)據(jù)結(jié)構(gòu)ArrayList的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-12-12
  • 使用BufferedReader讀取本地文件的操作

    使用BufferedReader讀取本地文件的操作

    這篇文章主要介紹了使用BufferedReader讀取本地文件的操作,具有很好的參考價值,希望對大家有所幫助。
    2021-07-07
  • Java單例模式的講解

    Java單例模式的講解

    今天小編就為大家分享一篇關于Java單例模式的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java中Jackson快速入門

    Java中Jackson快速入門

    這篇文章主要介紹了Java中Jackson快速入門,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01

最新評論