Mybatis学习 增强型注解简化SQL

【源】:https://blog.csdn.net/elricboa/article/details/78841376

1. 背景

MyBatis提供了简单的Java注解,使得我们可以不配置XML格式的Mapper文件,也能方便的编写简单的数据库操作代码:

  1. public interface UserMapper {  
  2.   @Select(“SELECT * FROM users WHERE id = #{userId}”)  
  3.   User getUser(@Param(“userId”) String userId);  
  4. }  
public interface UserMapper {
  @Select("SELECT * FROM users WHERE id = #{userId}")
  User getUser(@Param("userId") String userId);
}

但是注解对动态SQL的支持一直差强人意,即使MyBatis提供了InsertProvider等*Provider注解来支持注解的Dynamic SQL,也没有降低SQL的编写难度,甚至比XML格式的SQL语句更难编写和维护。

注解的优势在于能清晰明了的看见接口所使用的SQL语句,抛弃了繁琐的XML编程方式。但没有良好的动态SQL支持,往往就会导致所编写的DAO层中的接口冗余,所编写的SQL语句很长,易读性差……
Mybatis在3.2版本之后,提供了LanguageDriver接口,我们可以使用该接口自定义SQL的解析方式。故在这里向大家介绍下以此来实现注解方式下的动态SQL。

2. 实现方案

 我们先来看下LanguageDriver接口中的3个方法:
  1. public interface LanguageDriver {  
  2.     ParameterHandler createParameterHandler(MappedStatement var1, Object var2, BoundSql var3);  
  3.    
  4.     SqlSource createSqlSource(Configuration var1, XNode var2, Class<?> var3);  
  5.    
  6.     SqlSource createSqlSource(Configuration var1, String var2, Class<?> var3);  
  7. }  
public interface LanguageDriver {
    ParameterHandler createParameterHandler(MappedStatement var1, Object var2, BoundSql var3);

    SqlSource createSqlSource(Configuration var1, XNode var2, Class<?> var3);

    SqlSource createSqlSource(Configuration var1, String var2, Class<?> var3);
}
  1. createParameterHandler方法为创建一个ParameterHandler对象,用于将实际参数赋值到JDBC语句中
  2. 将XML中读入的语句解析并返回一个sqlSource对象
  3. 将注解中读入的语句解析并返回一个sqlSource对象

 

一旦实现了LanguageDriver,我们即可指定该实现类作为SQL的解析器,在XML中我们可以使用 lang 属性来进行指定
  1. <typeAliases>  
  2.   <typeAlias type=“org.sample.MyLanguageDriver” alias=“myLanguage”/>  
  3. </typeAliases>  
  4. <select id=“selectBlog” lang=“myLanguage”>  
  5.   SELECT * FROM BLOG  
  6. </select>  
<typeAliases>
  <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<select id="selectBlog" lang="myLanguage">
  SELECT * FROM BLOG
</select>

也可以通过设置指定解析器的方式:
  1. <settings>  
  2.   <setting name=“defaultScriptingLanguage” value=“myLanguage”/>  
  3. </settings>  
<settings>
  <setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>





如果不使用XML Mapper的形式,我们可以使用@Lang注解

  1. public interface Mapper {  
  2.   @Lang(MyLanguageDriver.class)   
  3.   @Select(“SELECT * FROM users”)  
  4.   List<User> selectUser();  
  5. }  
public interface Mapper {
  @Lang(MyLanguageDriver.class) 
  @Select("SELECT * FROM users")
  List<User> selectUser();
}
LanguageDriver的默认实现类为XMLLanguageDriver和RawLanguageDriver;分别为XML和Raw,Mybatis默认是XML语言,所以我们来看看XMLLanguageDriver中是怎么实现的:

 

  1. public class XMLLanguageDriver implements LanguageDriver {  
  2.     public XMLLanguageDriver() {  
  3.     }  
  4.    
  5.     public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {  
  6.         return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);  
  7.     }  
  8.    
  9.     public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {  
  10.         XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);  
  11.         return builder.parseScriptNode();  
  12.     }  
  13.    
  14.     public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {  
  15.         if(script.startsWith(“<script>”)) {  
  16.             XPathParser textSqlNode1 = new XPathParser(script, false, configuration.getVariables(),  
  17.                                        new XMLMapperEntityResolver());  
  18.             return this.createSqlSource(configuration, textSqlNode1.evalNode(“/script”), parameterType);  
  19.         } else {  
  20.             script = PropertyParser.parse(script, configuration.getVariables());  
  21.             TextSqlNode textSqlNode = new TextSqlNode(script);  
  22.             return (SqlSource)(textSqlNode.isDynamic()?new DynamicSqlSource(configuration, textSqlNode)  
  23.                    :new RawSqlSource(configuration, script, parameterType));  
  24.         }  
  25.     }  
  26. }  
public class XMLLanguageDriver implements LanguageDriver {
    public XMLLanguageDriver() {
    }

    public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
    }

    public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
        XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
        return builder.parseScriptNode();
    }

    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
        if(script.startsWith("<script>")) {
            XPathParser textSqlNode1 = new XPathParser(script, false, configuration.getVariables(),
                                       new XMLMapperEntityResolver());
            return this.createSqlSource(configuration, textSqlNode1.evalNode("/script"), parameterType);
        } else {
            script = PropertyParser.parse(script, configuration.getVariables());
            TextSqlNode textSqlNode = new TextSqlNode(script);
            return (SqlSource)(textSqlNode.isDynamic()?new DynamicSqlSource(configuration, textSqlNode)
                   :new RawSqlSource(configuration, script, parameterType));
        }
    }
}

发现其实mybatis已经帮忙写好了解析逻辑,而且发现如果是以<Script>开头的字符串传入后,会被以XML的格式进行解析。那么方案就可以确认了,我们继承XMLLanguageDriver这个类,并且重写其createSqlSource方法,按照自己编写逻辑解析好sql后,再调用父类的方法即可。

 

3. 实现自定义注解

本段中给出一些常见的自定义注解的实现和使用方式。

3.1 自定义Select In注解

 在使用Mybatis注解的时候,发现其对Select In格式的查询支持非常不友好,在字符串中输入<foreach>十分繁琐,可以通过将自定义的标签转成<foreach>格式;下面便通过我们自己实现的LanguageDriver来实现SQL的动态解析:

DAO接口层中代码如下:

  1. @Select(“SELECT * FROM users WHERE id IN (#{userIdList})”)  
  2. @Lang(SimpleSelectInLangDriver.class)  
  3. List<User> selectUsersByUserId(@Param(“userIdList”) List<Integer> userIdList);  
@Select("SELECT * FROM users WHERE id IN (#{userIdList})")
@Lang(SimpleSelectInLangDriver.class)
List<User> selectUsersByUserId(@Param("userIdList") List<Integer> userIdList);

  LanguageDriver实现类如下:

 

  1. // 一次编写即可  
  2. public class SimpleSelectInLangDriver extends XMLLanguageDriver implements LanguageDriver {  
  3.    
  4.     private static final Pattern inPattern = Pattern.compile(#\\{(\\w+)\\});  
  5.    
  6.     @Override  
  7.     public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {  
  8.    
  9.         Matcher matcher = inPattern.matcher(script);  
  10.         if (matcher.find()) {  
  11.             script = matcher.replaceAll(”<foreach collection=\”$1\” item=\”_item\” open=\”(\” ” +  
  12.                                         ”separator=\”,\” close=\”)\” >#{_item}</foreach>”);  
  13.         }  
  14.    
  15.    
  16.         script = ”<script>” + script + “</script>”;  
  17.         return super.createSqlSource(configuration, script, parameterType);  
  18.     }  
  19. }  
// 一次编写即可
public class SimpleSelectInLangDriver extends XMLLanguageDriver implements LanguageDriver {

    private static final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");

    @Override
    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {

        Matcher matcher = inPattern.matcher(script);
        if (matcher.find()) {
            script = matcher.replaceAll("<foreach collection=\"$1\" item=\"_item\" open=\"(\" " +
                                        "separator=\",\" close=\")\" >#{_item}</foreach>");
        }


        script = "<script>" + script + "</script>";
        return super.createSqlSource(configuration, script, parameterType);
    }
}

通过自己实现LanguageDriver,在服务器启动的时候,就会将我们自定义的标签解析为动态SQL语句,其等同于:

 

  1. @Select(“SELECT * ” +  
  2.         ”FROM users ” +  
  3.         ”WHERE id IN ” +  
  4.         ”<foreach item=’item’ index=’index’ collection=’list’ open=’(‘ separator=’,’ close=’)’>” +  
  5.         ”#{item}” +  
  6.         ”</foreach>”)  
  7. List<User> selectUsersByUserId(List<Integer> userIdList);  
@Select("SELECT * " +
        "FROM users " +
        "WHERE id IN " +
        "<foreach item='item' index='index' collection='list' open='(' separator=',' close=')'>" +
        "#{item}" +
        "</foreach>")
List<User> selectUsersByUserId(List<Integer> userIdList);

通过实现LanguageDriver,剥离了冗长的动态SQL语句,简化了Select In的注解代码。



需要注意的是在使用Select In的时候,请务必在传入的参数前加@Param注解,否则会导致Mybatic找不到参数而抛出异常。

3.2 自定义Update Bean注解

在扩展update注解时,数据库每张表的字段和实体类的字段必须遵循一个约定(数据库中采用下划线命名法,实体类中采用驼峰命名法)。当我们update的时候,会根据每个字段的映射关系,写出如下代码:

 

  1. <update id=“updateUsersById” parameterType=“com.lucifer.bean.User”>  
  2.     UPDATE users  
  3.         <set>  
  4.         <if test=“userName != null“>  
  5.             user_name = #{userName} ,  
  6.         </if>  
  7.         <if test=“password != null“>  
  8.             password = #{password} ,  
  9.         </if>  
  10.         <if test=“phone != null“>  
  11.             phone = #{phone},  
  12.         </if>  
  13.         <if test=“email != null“>  
  14.             email = #{email},  
  15.         </if>  
  16.         <if test=“address != null“>  
  17.             address = #{address},  
  18.         </if>  
  19.         <if test=“gmtCreated != null”>  
  20.             gmt_created = #{gmtCreated},  
  21.         </if>  
  22.         <if test=“gmtModified != null”>  
  23.             gmt_modified = #{gmtModified},  
  24.         </if>  
  25.     </set>  
  26.     WHERE id = #{id}  
  27. </update>   
<update id="updateUsersById" parameterType="com.lucifer.bean.User">
    UPDATE users
        <set>
        <if test=“userName != null">
            user_name = #{userName} ,
        </if>
        <if test=“password != null">
            password = #{password} ,
        </if>
        <if test=“phone != null">
            phone = #{phone},
        </if>
        <if test=“email != null">
            email = #{email},
        </if>
        <if test=“address != null">
            address = #{address},
        </if>
        <if test="gmtCreated != null">
            gmt_created = #{gmtCreated},
        </if>
        <if test="gmtModified != null">
            gmt_modified = #{gmtModified},
        </if>
    </set>
    WHERE id = #{id}
</update> 

我们可以将实体类中的驼峰式代码转换为下划线式命名方式,这样就可以将这种映射规律自动化



经过实现LanguageDriver后,注解代码为

 

  1. @Update(“UPDATE users (#{user}) WHERE id = #{id}”)  
  2. @Lang(SimpleUpdateLangDriver.class)  
  3. void updateUsersById(User user);  
@Update("UPDATE users (#{user}) WHERE id = #{id}")
@Lang(SimpleUpdateLangDriver.class)
void updateUsersById(User user);

相对于原始的代码量有很大的减少,并且,一个类中字段越多,改善也就越明显。实现方式为:
  1. public class SimpleUpdateLangDriver extends XMLLanguageDriver implements LanguageDriver{  
  2.    
  3.     private static final Pattern inPattern = Pattern.compile(#\\{(\\w+)\\});  
  4.    
  5.     @Override  
  6.     public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {  
  7.         Matcher matcher = inPattern.matcher(script);  
  8.         if (matcher.find()) {  
  9.             StringBuilder sb = new StringBuilder();  
  10.             sb.append(”<set>”);  
  11.    
  12.             for (Field field : parameterType.getDeclaredFields()) {  
  13.                 String tmp = ”<if test=\”_field != null\”>_column=#{_field},</if>”;  
  14.                 sb.append(tmp.replaceAll(”_field”, field.getName()).replaceAll(“_column”,  
  15.                         CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));  
  16.             }  
  17.    
  18.             sb.deleteCharAt(sb.lastIndexOf(”,”));  
  19.             sb.append(”</set>”);  
  20.    
  21.             script = matcher.replaceAll(sb.toString());  
  22.             script = ”<script>” + script + “</script>”;  
  23.         }  
  24.    
  25.         return super.createSqlSource(configuration, script, parameterType);  
  26.     }  
  27. }  
public class SimpleUpdateLangDriver extends XMLLanguageDriver implements LanguageDriver{

    private static final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");

    @Override
    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
        Matcher matcher = inPattern.matcher(script);
        if (matcher.find()) {
            StringBuilder sb = new StringBuilder();
            sb.append("<set>");

            for (Field field : parameterType.getDeclaredFields()) {
                String tmp = "<if test=\"_field != null\">_column=#{_field},</if>";
                sb.append(tmp.replaceAll("_field", field.getName()).replaceAll("_column",
                        CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));
            }

            sb.deleteCharAt(sb.lastIndexOf(","));
            sb.append("</set>");

            script = matcher.replaceAll(sb.toString());
            script = "<script>" + script + "</script>";
        }

        return super.createSqlSource(configuration, script, parameterType);
    }
}

3.3 自定义Insert Bean注解

同理,我们可以抽象化Insert操作,简化后的Insert注解为

 

  1. @Insert(“INSERT INTO users (#{user})”)  
  2. @Lang(SimpleInsertLangDriver.class)  
  3. void insertUserDAO(User user);  
@Insert("INSERT INTO users (#{user})")
@Lang(SimpleInsertLangDriver.class)
void insertUserDAO(User user);

实现方式为:

 

  1. public class SimpleInsertLangDriver extends XMLLanguageDriver implements LanguageDriver {  
  2.    
  3.     private static final Pattern inPattern = Pattern.compile(#\\{(\\w+)\\});  
  4.    
  5.     @Override  
  6.     public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {  
  7.    
  8.         Matcher matcher = inPattern.matcher(script);  
  9.         if (matcher.find()) {  
  10.             StringBuilder sb = new StringBuilder();  
  11.             StringBuilder tmp = new StringBuilder();  
  12.             sb.append(”(“);  
  13.    
  14.             for (Field field : parameterType.getDeclaredFields()) {  
  15.                 sb.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()) + ”,”);  
  16.                 tmp.append(”#{“ + field.getName() + “},”);  
  17.             }  
  18.    
  19.             sb.deleteCharAt(sb.lastIndexOf(”,”));  
  20.             tmp.deleteCharAt(tmp.lastIndexOf(”,”));  
  21.             sb.append(”) values (“ + tmp.toString() + “)”);  
  22.    
  23.             script = matcher.replaceAll(sb.toString());  
  24.             script = ”<script>” + script + “</script>”;  
  25.         }  
  26.    
  27.         return super.createSqlSource(configuration, script, parameterType);  
  28.     }  
  29. }  
public class SimpleInsertLangDriver extends XMLLanguageDriver implements LanguageDriver {

    private static final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");

    @Override
    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {

        Matcher matcher = inPattern.matcher(script);
        if (matcher.find()) {
            StringBuilder sb = new StringBuilder();
            StringBuilder tmp = new StringBuilder();
            sb.append("(");

            for (Field field : parameterType.getDeclaredFields()) {
                sb.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()) + ",");
                tmp.append("#{" + field.getName() + "},");
            }

            sb.deleteCharAt(sb.lastIndexOf(","));
            tmp.deleteCharAt(tmp.lastIndexOf(","));
            sb.append(") values (" + tmp.toString() + ")");

            script = matcher.replaceAll(sb.toString());
            script = "<script>" + script + "</script>";
        }

        return super.createSqlSource(configuration, script, parameterType);
    }
}

 

3.4 自定义Select注解

 

有的业务场景下,我们需要根据对象中的字段进行查询,就会写出如下代码:

 

  1. <select id=“selectUser” resultType=“com.lucifer.bean.User”>  
  2.     SELECT id,user_name,password,phone,address,email  
  3.     FROM users  
  4.     <where>  
  5.         <if test=“isDel != null”>  
  6.             AND is_del = #{isDel}  
  7.         </if>  
  8.         <if test=“userName != null”>  
  9.             AND user_name = #{userName}  
  10.         </if>  
  11.         <if test=“email != null”>  
  12.             AND email = #{email}  
  13.         </if>  
  14.         <if test=“phone != null”>  
  15.             AND phone = #{phone}  
  16.         </if>  
  17.     </where>  
  18. </select>  
<select id="selectUser" resultType="com.lucifer.bean.User">
    SELECT id,user_name,password,phone,address,email
    FROM users
    <where>
        <if test="isDel != null">
            AND is_del = #{isDel}
        </if>
        <if test="userName != null">
            AND user_name = #{userName}
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
        <if test="phone != null">
            AND phone = #{phone}
        </if>
    </where>
</select>



和Update操作一样,我们可以实现LanguageDriver将where子句抽象化,以此来简化Select查询语句。简化后代码如下:
  1. <select id=“selectUser” resultType=“com.lucifer.bean.User”>  
  2.     SELECT id,user_name,password,phone,address,email  
  3.     FROM users  
  4.     <where>  
  5.         <if test=“isDel != null”>  
  6.             AND is_del = #{isDel}  
  7.         </if>  
  8.         <if test=“userName != null”>  
  9.             AND user_name = #{userName}  
  10.         </if>  
  11.         <if test=“email != null”>  
  12.             AND email = #{email}  
  13.         </if>  
  14.         <if test=“phone != null”>  
  15.             AND phone = #{phone}  
  16.         </if>  
  17.     </where>  
  18. </select>  
<select id="selectUser" resultType="com.lucifer.bean.User">
    SELECT id,user_name,password,phone,address,email
    FROM users
    <where>
        <if test="isDel != null">
            AND is_del = #{isDel}
        </if>
        <if test="userName != null">
            AND user_name = #{userName}
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
        <if test="phone != null">
            AND phone = #{phone}
        </if>
    </where>
</select>

 

和Update操作一样,我们可以实现LanguageDriver将where子句抽象化,以此来简化Select查询语句。简化后代码如下:

  1. @Select(“SELECT id,user_name,password,phone,address,email FROM users (#{user})”)  
  2. @Lang(SimpleSelectLangDriver.class)  
  3. void selectUserDAO(User user)  
@Select("SELECT id,user_name,password,phone,address,email FROM users (#{user})")
@Lang(SimpleSelectLangDriver.class)
void selectUserDAO(User user)
  1. public class SimpleSelectLangDriver extends XMLLanguageDriver implements LanguageDriver {  
  2.    
  3.     private static final Pattern inPattern = Pattern.compile(#\\{(\\w+)\\});  
  4.    
  5.     @Override  
  6.     public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {  
  7.    
  8.         Matcher matcher = inPattern.matcher(script);  
  9.         if (matcher.find()) {  
  10.             StringBuilder sb = new StringBuilder();  
  11.             sb.append(”<where>”);  
  12.    
  13.             for (Field field : parameterType.getDeclaredFields()) {  
  14.                 String tmp = ”<if test=\”_field != null\”>AND _column=#{_field}</if>”;  
  15.                 sb.append(tmp.replaceAll(”_field”, field.getName()).replaceAll(“_column”,  
  16.                         CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));  
  17.             }  
  18.    
  19.             sb.append(”</where>”);  
  20.    
  21.             script = matcher.replaceAll(sb.toString());  
  22.             script = ”<script>” + script + “</script>”;  
  23.         }  
  24.    
  25.         return super.createSqlSource(configuration, script, parameterType);  
  26.     }  
  27. }  
public class SimpleSelectLangDriver extends XMLLanguageDriver implements LanguageDriver {

    private static final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");

    @Override
    public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {

        Matcher matcher = inPattern.matcher(script);
        if (matcher.find()) {
            StringBuilder sb = new StringBuilder();
            sb.append("<where>");

            for (Field field : parameterType.getDeclaredFields()) {
                String tmp = "<if test=\"_field != null\">AND _column=#{_field}</if>";
                sb.append(tmp.replaceAll("_field", field.getName()).replaceAll("_column",
                        CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));
            }

            sb.append("</where>");

            script = matcher.replaceAll(sb.toString());
            script = "<script>" + script + "</script>";
        }

        return super.createSqlSource(configuration, script, parameterType);
    }
}



 

4.排除多余的变量

 一个常见的情况是,可能会遇到实体类中的部分字段在数据库中并不存在相应的列,这就需要对多余的不匹配的字段进行逻辑隐藏;我们增加一个自定义的注解,并且对Language的实现稍作修改即可。
注解为:

 

  1. @Target(ElementType.FIELD)  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface Invisible {  
  4. }  
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Invisible {
}
  1. public class User {  
  2.     …  
  3.       
  4.     @Invisible  
  5.     private List<String> userList;  
  6.    
  7.    
  8.     …  
  9. }  
public class User {
    ...

    @Invisible
    private List<String> userList;


    ...
}

 

然后在实现类中将被该注解声明过的字段排除

  1. for (Field field : parameterType.getDeclaredFields()) {  
  2.     if (!field.isAnnotationPresent(Invisible.class)) {  // 排除被Invisble修饰的变量  
  3.         String tmp = ”<if test=\”_field != null\”>_column=#{_field},</if>”;  
  4.         sb.append(tmp.replaceAll(”_field”, field.getName()).replaceAll(“_column”,  
  5.                 CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));  
  6.     }  
  7. }  
for (Field field : parameterType.getDeclaredFields()) {
    if (!field.isAnnotationPresent(Invisible.class)) {  // 排除被Invisble修饰的变量
        String tmp = "<if test=\"_field != null\">_column=#{_field},</if>";
        sb.append(tmp.replaceAll("_field", field.getName()).replaceAll("_column",
                CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));
    }
}

 
  1. for (Field field : parameterType.getDeclaredFields()) {  
  2.     if (!field.isAnnotationPresent(Invisible.class)) {  // 排除被Invisble修饰的变量  
  3.         String tmp = ”<if test=\”_field != null\”>_column=#{_field},</if>”;  
  4.         sb.append(tmp.replaceAll(”_field”, field.getName()).replaceAll(“_column”,  
  5.                 CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));  
  6.     }  
  7. }  
for (Field field : parameterType.getDeclaredFields()) {
    if (!field.isAnnotationPresent(Invisible.class)) {  // 排除被Invisble修饰的变量
        String tmp = "<if test=\"_field != null\">_column=#{_field},</if>";
        sb.append(tmp.replaceAll("_field", field.getName()).replaceAll("_column",
                CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName())));
    }
}

5.注意事项&遇到的一些坑

  1. 务必确保数据库中列名和实体类中字段能一一对应
  2. 在使用自定义SQL解析器的时候,只能传入一个参数,即相应的对象参数即可;传入多个参数会导致解析器中获得到的class对象改变,使得sql解析异常
  3. Update的实现能满足大部分的业务,但有些业务场景可以会遇到根据查询条件来更新查询参数的情况,比如Update uesrs SET uesr_name = ‘tom’ WHERE user_name = ‘Jack’; 在这中场景的时候请不要使用自定义的SQL解析器
  4. 请使用Mybatis 3.3以上版本。3.2版本有bug,会另开一篇重新描述

6.总结

 通过实现Language Driver,我们可以方便的自定义自己的注解。在遵循一些约定的情况下(数据库下划线命名,实体驼峰命名),我们可以大幅度的减少SQL的编写量,并且可以完全的屏蔽掉麻烦的XML编写方式,再也不用编写复杂的动态SQL了有木有。


  1. // 简洁的数据库操作  
  2.    
  3. @Select(“SELECT * FROM users WHERE id IN (#{userIdList})”)  
  4. @Lang(SimpleSelectInLangDriver.class)  
  5. List<User> selectUsersByUserId(List<Integer> userIdList);  
  6.    
  7.    
  8. @Insert(“INSERT INTO users (#{user})”)  
  9. @Lang(SimpleInsertLangDriver.class)  
  10. void insertUserDAO(User user);  
  11.    
  12.    
  13. @Update(“UPDATE users (#{user}) WHERE id = #{id}”)  
  14. @Lang(SimpleUpdateLangDriver.class)  
  15. void updateUsersById(User user);  
  16.     
  17. @Select(“SELECT id,user_name,password,phone,address,email FROM users (#{user})”)  
  18. @Lang(SimpleSelectLangDriver.class)  
  19. void selectUserDAO(User user);  
// 简洁的数据库操作

@Select("SELECT * FROM users WHERE id IN (#{userIdList})")
@Lang(SimpleSelectInLangDriver.class)
List<User> selectUsersByUserId(List<Integer> userIdList);


@Insert("INSERT INTO users (#{user})")
@Lang(SimpleInsertLangDriver.class)
void insertUserDAO(User user);


@Update("UPDATE users (#{user}) WHERE id = #{id}")
@Lang(SimpleUpdateLangDriver.class)
void updateUsersById(User user);

@Select("SELECT id,user_name,password,phone,address,email FROM users (#{user})")
@Lang(SimpleSelectLangDriver.class)
void selectUserDAO(User user);








阅读更多
换一批

没有更多推荐了,返回首页