preface

Mybatis (myBatis, mybatis, mybatis, mybatis, mybatis, mybatis, mybatis, mybatis, mybatis)


<if test="type! =null and type ! = "">  
    and status = 1   
</if>

Copy the code

So there is not enough attention paid to this area.

The body of the

The last thing I want to do is write something different, but based on the above, to determine the value of the attribute: Determine the value of the type attribute


<if test="type! =null and type ! = "">  
    <if test="type=='6'">  
        and status = 61   
    </if>
    <if test="type! = '6'. "">  
        and status = 2  
    </if>
</if>

Copy the code

The result is that no matter what value I pass, status=2 is executed in SQL. I also found a lot of solutions on the Internet, but they are not what I want;

Online solutions

  1. The double outside the single

<if test='type=="6"'>  
    and status = 1   
</if>

Copy the code
  1. Gal. ToString ()

<if test="type=='6'.toString()">  
    and status = 1   
</if>

Copy the code

Source code analysis

Mybatis uses ogNL expressions for parsing. The following uses OGNL to simulate parsing; Do not use either of the above methods;

The introduction of pom

    <dependency>
         <groupId>ognl</groupId>
         <artifactId>ognl</artifactId>
         <version>3.21.</version>
     </dependency>
Copy the code

Test code:


       // Build an OgnlContext object
       OgnlContext context = (OgnlContext) Ognl.createDefaultContext(this.new DefaultClassResolver(),
               new DefaultTypeConverter(),
               new DefaultMemberAccess(true));

       Map<String,Object> hashMap=new HashMap<>(1);
       hashMap.put("name"."aa");
       context.setRoot(hashMap);
       String expression="name =='aa'";
       try {
           Boolean flag = (Boolean) Ognl.getValue(expression, context, context.getRoot());
           System.out.println(flag);
       } catch (OgnlException e) {
           e.printStackTrace();
       }

Copy the code

Your own solution

In addition to the two ways on the Internet, there are some other ways to solve the problem I encountered;

  1. Since I am comparing a numeric type, change the value passed in to a numeric type and remove the single quotes from mybatis XML, as follows:
        
       hashMap.put("name".6);
       context.setRoot(hashMap);
       String expression="name ==6";
Copy the code

Ognl source code parsing

The following is the analysis of the source code of OGNL:

1. Locate the isEqual method of OgnlOps class according to the ogNL. getValue method

    
    public static boolean isEqual(Object object1, Object object2)
    {
        boolean result = false;
// 1. Check whether the two objects are the same
        if (object1 == object2) {
            result = true;
        } else {
// 2. Set judgment
            if((object1 ! =null) && object1.getClass().isArray()) {
                if((object2 ! =null) && object2.getClass().isArray() && (object2.getClass() == object1.getClass())) { result = (Array.getLength(object1) ==  Array.getLength(object2));if (result) {
                        for(int i = 0, icount = Array.getLength(object1); result && (i < icount); i++) { result = isEqual(Array.get(object1, i), Array.get(object2, i)); }}}}else {
// 3. Non-set judgment
// 3.1 If both values are String, return equals directly. If not, enter compareWithConversion;
                // Check for converted equivalence first, then equals() equivalence result = (object1 ! =null) && (object2 ! =null)&& (object1.equals(object2) || (compareWithConversion(object1, object2) == 0)); }}return result;
    }

Copy the code

The first value is the value passed in the mybatis method. This value can be of a variety of types, such as BigDecimal, String, Integer, etc. The second value is read from the MYbatis XML file. This value is determined by the way the XML file is written:

  1. Double single

1.1 When the length is 1, the value is read as Character. 1.2 When the length is greater than 1, the value is read as String

Then locate the compareWithConversion method based on the third judgment

2. CompareWithConversion method

  1. This method uses getNumericType method to judge the parameter number type. In fact, it can be judged according to the method name. After entering here, it is to judge the number type, then convert, and then compare
  2. During conversion, if the character passed in cannot be converted, an error will be thrown. For example, if the value passed in is a letter, it cannot be converted.
  3. If mybatis has an XML file with a judgment value of “” or “”, this method will assign the value to 0;
  4. When mybatis XML file judgment value is “”, and the value inside is a single value, notice that the converted value is not the original value; For example: ‘6’ resolves to double:54.0

public static int compareWithConversion(Object v1, Object v2)
    {
        int result;
        if (v1 == v2) {
            result = 0;
        } else {
            / / 1
            int t1 = getNumericType(v1), t2 = getNumericType(v2), type = getNumericType(t1, t2, true);
            switch(type) {
            case BIGINT:
                result = bigIntValue(v1).compareTo(bigIntValue(v2));
                break;
            case BIGDEC:
                result = bigDecValue(v1).compareTo(bigDecValue(v2));
                break;
            case NONNUMERIC:
                if ((t1 == NONNUMERIC) && (t2 == NONNUMERIC)) {
                    if ((v1 instanceof Comparable) && v1.getClass().isAssignableFrom(v2.getClass())) {
                        result = ((Comparable) v1).compareTo(v2);
                        break;
                    } else {
                        throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and "+ v2.getClass().getName()); }}// else fall through
            case FLOAT:
            case DOUBLE:
                // Note that the doubleValue method throws an error when the value passed in is a letter;
                double dv1 = doubleValue(v1),
                dv2 = doubleValue(v2);
                return (dv1 == dv2) ? 0 : ((dv1 < dv2) ? -1 : 1);
            default:
                long lv1 = longValue(v1),
                lv2 = longValue(v2);
                return (lv1 == lv2) ? 0 : ((lv1 < lv2) ? -1 : 1); }}return result;
    }

Copy the code

conclusion

  1. If the property is not of numeric type, using the above online solution will do the job

  2. There is a problem if the attribute is of numeric type, such as Integer, BigDecimal, and so on

If the value passed in is 0 and the comparison is “” or “” in the myBatis XML file, the result of the comparison is false, as follows:


    // 1 double quote "", pass in a value of 0, or some other value of 0
    hashMap.put("name".0); 
    hashMap.put("name",BigDecimal.ZERO);
    String expression="name! =null and name! = \ "\" ";

    // 2 Single quotation marks are passed in with a value of 0 or some other type of 0
    hashMap.put("name".0);
    hashMap.put("name",BigDecimal.ZERO);
    String expression="name! =null and name! = "";

Copy the code

The solution:

  1. Converts the passed value type to String
  2. In mybatis, modify the XML as follows:

    <if test="infSrc ! = null and infSrc! = "">AND INF_SRC = #{infSrc,jdbcType=BIGINT}</if>
    / / or
    <if test="infSrc ! = null and infSrc! = "">AND INF_SRC = #{infSrc,jdbcType=DECIMAL}</if>

Copy the code

This depends on the type of value you pass in;

The last

Project address: github.com/guodayede/j…

Refer to the article

  1. Pit of myBatis’ if test string
  2. Mybatis if test String comparison does not take effect
  3. Mandatory object type of OGNL expression in MyBatis