Mybatis 实现动态组装查询条件,仿SQL模式

目的:

以前比较习惯使用Hibernate,后来觉得mybatis不能按我想要的自动组装为SQL查询条件,所以提供该工具类;

效果图:

如图所示,根据条件自动组装查询条件,下面来说一下实现方法:

1. ServiceImpl书写注意项

        Page<SysLogin> resultPage = null;
        try {
            PageHelper.startPage(pager.getCurrentPage(), pager.getPageSize());
            // 判断是否有分页
            if (ObjectHelper.isNotEmpty(pager.getDirection())
                    && ObjectHelper.isNotEmpty(pager.getProperties())) {
                specification.addOrderBy(pager.getProperties(),
                        pager.getDirection());
            }
            // 判断是否存在逻辑删除筛选
            String sqlStr = specification.sql();
            if (sqlStr.indexOf("deleted") == -1) {
                specification.eq("deleted", "0");
            }
            resultPage = this.sysLoginMapper.page(specification.sql());
        } catch (Exception e) {
            result = Result.newFailure("数据错误", "在获取分页列表时发生异常。");
            log.error(SimpleLogFormater.formatException(result.getMessage(), e));
            return result;
        }

2. Mapper.java 书写

查询条件非Map对象,直接就是SQL语句了;

    /**
     * 分页查询数据
     *
     * @return
     */
    Page<T> page(String sqlStr);

3. 关于XML的配置,会拼装SQL语句

附:SQL拼装工具类

/**
 * @Description: (用一句话描述该文件做什么)
 * @author heliang
 * @date 2018-7-6 下午6:43:42
 * @version V2.1
 */
package com.onem2.base.common;
import com.onem2.base.helper.ObjectHelper;

/**
 * @ClassName: Specification
 * @Description: (这里用一句话描述这个类的作用)
 * @author heliang
 * @date 2018-7-6 下午6:43:42
 * @version V2.1 * Update Logs: * Name: * Date: * Description: 初始化
 */

public class Specification {

    private StringBuilder where = new StringBuilder();
    private String groupBy;
    private String having;
    private String orderBy;

    public StringBuilder getWhere() {
        return where;
    }

    public void setWhere(StringBuilder where) {
        this.where = where;
    }

    public String getGroupBy() {
        return groupBy;
    }

    public void setGroupBy(String groupBy) {
        this.groupBy = groupBy;
    }

    public String getHaving() {
        return having;
    }

    public void setHaving(String having) {
        this.having = having;
    }

    public String getOrderBy() {
        return orderBy;
    }

    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }

    public Specification addOrderBy(String sort, String order) {
        if (!isEmpty(sort) && !isEmpty(order)) {
            this.orderBy = ObjectHelper.underscoreName(sort) + " " + order;
        }
        return this;
    }

    public Specification orLike(String value, String columns) {
        if (!isEmpty(value)) {
            StringBuffer strBuf = new StringBuffer("");
            for (String column : columns.split(",")) {
                strBuf.append(ObjectHelper.underscoreName(column) + " like '%"
                        + value + "%' or ");
            }
            String orLikeStr = strBuf.substring(0, strBuf.lastIndexOf("or"));
            where.append(" and (" + orLikeStr + ")");
        }
        return this;
    }

    public Specification eq(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column) + " = '"
                    + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification ne(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " != '" + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification like(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " like '%" + sqlParam(value) + "%'");
        }
        return this;
    }

    public Specification notLike(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " not like '%" + sqlParam(value) + "%'");
        }
        return this;
    }

    public Specification in(String column, String... values) {
        if (!isEmpty(values)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " in (" + inValuesString(values) + ")");
        }
        return this;
    }

    public Specification notIn(String column, String... values) {
        if (!isEmpty(values)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " not in (" + inValuesString(values) + ")");
        }
        return this;
    }

    public Specification gt(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column) + " > '"
                    + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification gte(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " >= '" + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification lt(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column) + " < '"
                    + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification lte(String column, String value) {
        if (!isEmpty(value)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " <= '" + sqlParam(value) + "'");
        }
        return this;
    }

    public Specification between(String column, String from, String to) {
        if (isEmpty(from) && isEmpty(to)) {
            return this;
        }
        if (isEmpty(to)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " >= '" + sqlParam(from) + "'");
        } else if (isEmpty(from)) {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " <= '" + sqlParam(to) + "'");
        } else {
            where.append(" and " + ObjectHelper.underscoreName(column)
                    + " between '" + sqlParam(from) + "' and '" + sqlParam(to)
                    + "'");
        }
        return this;
    }

    public String sql() {
        StringBuilder sql = new StringBuilder("");
        final int a = 4;
        final int b = 5;
        if (where.length() > a) {
            sql.append(" " + where.substring(b));
        }
        if (!isEmpty(groupBy)) {
            sql.append(" group by " + groupBy);
        }
        if (!isEmpty(having)) {
            sql.append(" having " + having);
        }
        if (!isEmpty(orderBy)) {
            sql.append(" order by " + orderBy);
        }
        return sql.toString();
    }

    public String toString() {
        return sql();
    }

    private static boolean isEmpty(String value) {
        return value == null || "".equals(value) || value.trim().length() == 0;
    }

    private static boolean isEmpty(String[] values) {
        if (values == null || values.length == 0) {
            return true;
        }
        for (String value : values) {
            if (!isEmpty(value)) {
                return false;
            }
        }
        return true;
    }

    private static String inValuesString(String[] values) {
        StringBuilder string = new StringBuilder();
        for (String value : values) {
            if (isEmpty(value)) {
                continue;
            }
            string.append('\'');
            string.append(value);
            string.append('\'');
            string.append(',');
        }
        if (string.length() > 0) {
            string.deleteCharAt(string.length() - 1);
        }
        return string.toString();
    }

    private static String sqlParam(String sqlParam) {
        return sqlParam.replaceAll("([';]+|(--)+)", "");
    }
}

附:ObjectHelper 工具源码:

package com.onem2.base.helper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
 * Object帮助类 功能:此类提供处理 <Object>对象一系列方法
 *
 * @author 贺亮
 *
 */
public class ObjectHelper {

    /**
     * 将id数组转换为id集合
     *
     * @param ids
     * @return
     */
    public static List<Long> initIds(String[] ids) {
        List<Long> list = new ArrayList<Long>();
        list.add(-1L);
        for (int i = 0; i < ids.length; i++) {
            list.add(Long.valueOf(ids[i]));
        }
        return list;
    }

    /**
     * 组装条件
     *
     * @param str
     * @return
     */
    public static List<String> strToList(String str) {
        if (isEmpty(str)) {
            return null;
        }
        String[] strs = str.split(",");
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < strs.length; i++) {
            list.add(strs[i]);
        }
        return list;
    }

    /**
     * 判断这个Object是否为Null或长度为0
     *
     * @param obj
     * @return
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }

        if (obj instanceof String) {
            return ((String) obj).equalsIgnoreCase("null")
                    | ((String) obj).trim().toString().equals("");
        }

        if (obj instanceof StringBuffer) {
            return ((StringBuffer) obj).length() == 0;
        }

        if (obj.getClass().isArray()) {
            try {
                Object[] a = (Object[]) obj;

                boolean b = true;
                for (Object o : a) {
                    b = b & isEmpty(o);

                    if (!b) {
                        break;
                    }
                }

                return b;
            } catch (ClassCastException e) {
            }
        }
        return false;
    }

    /**
     * 判断这个Object是否不为Null或长度不为0
     *
     * @param obj
     * @return
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    /**
     * 返回首字母大写单词
     *
     * @param str
     * @return
     */
    public static String lcyFirstLetterToUpper(String str) {
        return str.replaceFirst(str.substring(0, 1), str.substring(0, 1)
                .toUpperCase());
    }

    /**
     * 转换为下划线
     *
     * @param camelCaseName
     * @return
     */
    public static String underscoreName(String camelCaseName) {
        StringBuilder result = new StringBuilder();
        if (camelCaseName != null && camelCaseName.length() > 0) {
            result.append(camelCaseName.substring(0, 1).toLowerCase());
            for (int i = 1; i < camelCaseName.length(); i++) {
                char ch = camelCaseName.charAt(i);
                if (Character.isUpperCase(ch)) {
                    result.append("_");
                    result.append(Character.toLowerCase(ch));
                } else {
                    result.append(ch);
                }
            }
        }
        return result.toString();
    }

    /**
     * 转换为驼峰
     *
     * @param underscoreName
     * @return
     */
    public static String camelCaseName(String underscoreName) {
        StringBuilder result = new StringBuilder();
        if (underscoreName != null && underscoreName.length() > 0) {
            boolean flag = false;
            for (int i = 0; i < underscoreName.length(); i++) {
                char ch = underscoreName.charAt(i);
                if ("_".charAt(0) == ch) {
                    flag = true;
                } else {
                    if (flag) {
                        result.append(Character.toUpperCase(ch));
                        flag = false;
                    } else {
                        result.append(ch);
                    }
                }
            }
        }
        return result.toString();
    }

    public static void main(String[] args) {
        System.out.println(underscoreName("loginName"));
    }
}

这样就可以做到动态生成查询条件,复杂的查询条件也不会去改动XML配置了。

mybatis原理:参数解析与SQL动态组装过程

mybatis执行sql之前, 需要经过参数解析、sql动态组装等过程,本文主要聊聊mybatis的:

(1)参数解析原理及其过程

(2)sql动态组装原理及其过程

一、数据准备

1.实体类,省略了set、get方法

public class User {
    private String id;
    private String username;
    private String password;
    private Integer isValid;
}

2.mapper接口UserMapper,可以看作是一个根据用户名和密码的登录接口

User getUserByUsernameAndPassword(@Param("name") String username, @Param("pwd") String password);

3.mapper映射

<select id="getUserByUsernameAndPassword" resultType="com.qxf.pojo.User">
        select id,username,password,is_valid as isValid from t_user
        <where>
            <if test="name != null and name != ''">
                username = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and password = #{pwd}
            </if>
        </where>
    </select>

4.测试,mybatis-config.xml配置文件按一般配置即可,这里就不贴代码了

//读取配置信息
        InputStream  inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //根据配置信息,创建SqlSession工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //SqlSession工厂创建SqlSession
        SqlSession sqlSession = factory.openSession();
        //获取接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //执行相应的接口方法
        User user = mapper.getUserByUsernameAndPassword("张三2", null);
        System.out.println(user);

下面将以这句代码为入口:

(注意,这里只是为了测试,给密码参数传递了null,正常情况不会这样传递参数的,不然结果返回一个List集合就会报错的)

//执行相应的接口方法
User user = mapper.getUserByUsernameAndPassword("张三2", null);

二、参数解析原理及其过程

首先要明白一点,返回的是mapper接口的代理对象,所以会来到MapperProxy的invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // Object对象的方法,则直接执行
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }

            if (method.isDefault()) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
        // 获取mapperMethod,这里面就会进行参数解析
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        // 执行方法
        return mapperMethod.execute(this.sqlSession, args);
    }

重点关注这句:

        // 获取mapperMethod,这里面就会进行参数解析
        MapperMethod mapperMethod = this.cachedMapperMethod(method);

参数的解析可以分成两部:

(1)形参的解析

(2)实参的封装

(1)形成的解析

一路跟进去,最终会来到 ParamNameResolver,暂且叫做参数名称解析器吧,首先会在构造器组装参数的位置和名称的对应关系,如果我们使用了@Param注解,则会使用我们定义的名称,否则会使用arg0、arg1....依次替代,详细代码如下:

public ParamNameResolver(Configuration config, Method method) {
        // 获取参数列表中,每一个参数的类型
        Class<?>[] paramTypes = method.getParameterTypes();
        // 获取参数注解,因为每个参数可能有多个注解,所以是二维数组
        Annotation[][] paramAnnotations = method.getParameterAnnotations();
        // 存放结果的map
        SortedMap<Integer, String> map = new TreeMap();
        // 参数个数
        int paramCount = paramAnnotations.length;

        for(int paramIndex = 0; paramIndex < paramCount; ++paramIndex) {
            if (!isSpecialParameter(paramTypes[paramIndex])) {
                // 参数名称
                String name = null;
                // 参数的注解数组
                Annotation[] var9 = paramAnnotations[paramIndex];
                // 参数注解的个数
                int var10 = var9.length;
                // 遍历每个注解,找到Param注解,拿到value作为参数名称
                for(int var11 = 0; var11 < var10; ++var11) {
                    Annotation annotation = var9[var11];
                    if (annotation instanceof Param) {
                        this.hasParamAnnotation = true;
                        name = ((Param)annotation).value();
                        break;
                    }
                }

                if (name == null) {
                    if (config.isUseActualParamName()) {
                        name = this.getActualParamName(method, paramIndex);
                    }

                    if (name == null) {
                        name = String.valueOf(map.size());
                    }
                }
                // 参数序号作为key,从0开始,参数名称作为值
                map.put(paramIndex, name);
            }
        }
        // 没有做什么,再一次封装而已
        this.names = Collections.unmodifiableSortedMap(map);
    }

结果是这样的:符合我们的预期的

(2)实参的封装

然后会来到getNamedParams方法对参数进一步的封装:

  public Object getNamedParams(Object[] args) {
        // 参数个数,这个names就是上面解析后的map,key是从0开始的参数序号,value是参数名称
        int paramCount = this.names.size();
        // 这里的args便是实参列表
        // 实参不为空,形参个数不为0
        if (args != null && paramCount != 0) {
            if (!this.hasParamAnnotation && paramCount == 1) {
                // 没有使用@Param注解,并且只有一个参数
                return args[(Integer)this.names.firstKey()];
            } else {
                // 将参数封装成一个map
                Map<String, Object> param = new ParamMap();
                int i = 0;
                // 对形参循环迭代
                for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
                    Entry<Integer, String> entry = (Entry)var5.next();
                    // names中的参数名称为key,值为实参值
                    param.put((String)entry.getValue(), args[(Integer)entry.getKey()]);
                    // 并添加key为param1、param2之类的通用参数
                    String genericParamName = "param" + String.valueOf(i + 1);
                    if (!this.names.containsValue(genericParamName)) {
                        param.put(genericParamName, args[(Integer)entry.getKey()]);
                    }
                }

                return param;
            }
        } else {
            return null;
        }
    }

通过源码可以发现,

(1)如果只有一个参数,并且没有使用@Param注解,就直接返回第一个参数

(2)有多个参数,则封装成一个map,key为参数参数名称,使用了@Param注解,名称就是注解中的值,否则key为arg0、arg1这种类型,同时,一定含有key为param1、param2的参数,值就是传入的值

封装后的结果如下:

这样就完成了参数的解析过程,总结一下:

(1)解析形参,判断是否使用了@Param注解

(2)封装实参,如果只有一个,并且没有使用@Param注解,就直接返回第一个参数值,否则封装成map

三、动态组装sql原理及其过程

来到CachingExecutor的如下方法,作为入口:

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        // 获取组装完成的sql
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        // 创建缓存key
        CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
        // 执行查询
        return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

重点看这句:

        // 获取组装完成的sql
        BoundSql boundSql = ms.getBoundSql(parameterObject);

一路跟进去,来到DynamicSqlSource的getBoundSql方法:

   public BoundSql getBoundSql(Object parameterObject) {
        // 将参数封装成动态上下文,DynamicContext中sqlBuilder就是最后组装的sql
        DynamicContext context = new DynamicContext(this.configuration, parameterObject);
        // 根据条件,动态组装sql
        this.rootSqlNode.apply(context);
        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(this.configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        // 将#{参数}替换为?
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        Map var10000 = context.getBindings();
        Objects.requireNonNull(boundSql);
        var10000.forEach(boundSql::setAdditionalParameter);
        return boundSql;
    }

我们先看下这句:

// 根据条件,动态组装sql
this.rootSqlNode.apply(context);

对于我们的sql:

    <select id="getUserByUsernameAndPassword" resultType="com.qxf.pojo.User">
        select id,username,password,is_valid as isValid from t_user
        <where>
            <if test="name != null and name != ''">
                username = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and password = #{pwd}
            </if>
        </where>
    </select>

每个标签都有对应的SqlNode来处理,比如if标签,就由IfSqlNode来处理,where标签,则会通过TrimSqlNode来处理,SqlNode的具体实现类如下:

这里以IfSqlNode处理if标签为例:

这是就是两步:

(1)判断表达式的值是否为真,这里最终使用的是Ognl来判断

(2)如果表达式的为真,就将标签内容追加到sql中去

处理结果如下:

因为密码的参数传入为null,所以不会拼接密码查询条件,只拼接了用户名查询条件

然后是将#{参数}替换为?进行占位:

        // 将#{参数}替换为?
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());

这个就比较简单了,可以自行看源码,最终是这样的:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • mybatis动态sql之Map参数的讲解

    mybatis 动态sql之Map参数 Mapper文件: <mapper namespace="com.cn.shoje.oa.modules.logistics.dao.PurcDao"> <select id="findAll" parameterType="Map" resultType="Purchase"> select * from prod_purchase where 1=1 <

  • MyBatis动态SQL实现配置过程解析

    动态SQL 什么是动态SQL: ​ 动态SQL就是根据不同的条件生成不同的SQL语句 if choose(when,otherwise) trim(where,set) foreach 1.搭建环境 建表 CREATE TABLE `bolg`( `id` VARCHAR(50) NOT NULL COMMENT '博客id', `title` VARCHAR(100) not null comment '博客标题', `author` VARCHAR(30) not null comment

  • Mybatis中输入输出映射与动态Sql图文详解

    一.输入映射 我们通过配置parameterType的值来指定输入参数的类型,这些类型可以是简单数据类型.POJO.HashMap等数据类型 1.简单类型 2.POJO包装类型 ①这是单表查询的时候传入的POJO包装类型,即可以直接传入实体类,但是当多表查询的时候,就需要自定义POJO类型 ②我们使用自定义POJO类型来具体的了解一下 先设计 包装类型如下,其中UserPOJO是除了User本身之外的添加的其他跟User相关的属性的包装类,UserVo是用于视图层面的包装类型,同样也是作为Map

  • mybatis的动态sql详解(精)

    MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力.如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号.动态 SQL 可以彻底处理这种痛苦. 通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中. 动态SQL元素和使用 JSTL或其他相似的基于XML的文本处理器相似.在MyBatis之前的版本中,有很多

  • Mybatis 实现动态组装查询条件,仿SQL模式

    目的: 以前比较习惯使用Hibernate,后来觉得mybatis不能按我想要的自动组装为SQL查询条件,所以提供该工具类: 效果图: 如图所示,根据条件自动组装查询条件,下面来说一下实现方法: 1. ServiceImpl书写注意项 Page<SysLogin> resultPage = null; try { PageHelper.startPage(pager.getCurrentPage(), pager.getPageSize()); // 判断是否有分页 if (ObjectHel

  • MyBatisPlus查询投影与查询条件详细讲解

    目录 查询投影 查询指定字段 聚合查询 分组查询 查询条件 等值查询 范围查询 模糊查询 排序查询 查询投影 查询指定字段 目前我们在查询数据的时候,什么都没有做默认就是查询表中所有字段的内容,我们所说的查询投影即不查询所有字段,只查询出指定内容的数据. 具体如何来实现? @SpringBootTest class Mybatisplus02DqlApplicationTests { @Autowired private UserDao userDao; @Test void testGetAl

  • mybatis的动态SQL和模糊查询实例详解

    现在以一个例子来介绍mybatis的动态SQL和模糊查询:通过多条件查询用户记录,条件为姓名模糊匹配,并且年龄在某两个值之间. 新建表d_user: create table d_user( id int primary key auto_increment, name varchar(10), age int(3) ); insert into d_user(name,age) values('Tom',12); insert into d_user(name,age) values('Bob

  • JPA多条件复杂SQL动态分页查询功能

    概述 ORM映射为我们带来便利的同时,也失去了较大灵活性,如果SQL较复杂,要进行动态查询,那必定是一件头疼的事情(也可能是lz还没发现好的方法),记录下自己用的三种复杂查询方式. 环境 springBoot IDEA2017.3.4 JDK8 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0&q

  • MyBatis中动态sql的实现方法示例

    1. 动态sql 动态sql是mybatis中的一个核心,什么是动态sql? 动态sql即对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. MyBatis的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号.有些时候,SQL语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可

  • MyBatis常用动态sql大总结

    简介 相信大家没用Mybatis之前,都碰到过各种条件判断拼接SQL.需要去掉多余的逗号等痛苦,Mybatis中的动态SQL能很好的解决上面说的情况,可以很灵活的组装SQL语句,从而提高开发效率. 1.SQL的动态拼接有哪些 if标签 where标签 choose when otherwise标签 set标签 trim标签 bind标签 sql和include标签 foreach标签 2.if标签: test中写判断条件 参数直接paramN或者别名 特点: 只要成立就拼接在Sql语句中,都成立

  • MyBatis 执行动态 SQL语句详解

    大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: <select id="executeSql" resultType="map"> ${_parameter} </select> 你可以如下调用: sqlSession.selectList("executeSql", "select * from sysuser where enabled

  • MyBatis使用动态SQL标签的小陷阱

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 现在MyBatis越来越受大家的喜爱了,它的优势大家都知道,我就不多说了,直接说重点. MyBatis中提供动态SQL功能,我们可以使用<if><when&

  • Mybatis中动态SQL,if,where,foreach的使用教程详解

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.statement中直接定义使用动态SQL: 在statement中利用if 和 where 条件组合达到我们的需求,通过一个例子来说明: 原SQL语句

  • MyBatis执行动态SQL的方法

    大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: <select id="executeSql" resultType="map"> ${_parameter} </select> 你可以如下调用: sqlSession.selectList("executeSql", "select * from sysuser where enabled

随机推荐