为什么推荐选择Mybatis Dynamic SQL

为什么选择Mybatis Dynamic SQL?

MBG已经推荐所有的java新项目,都采用Mybatis Dynamic SQL,以java API的方式书写SQL,而不是XML。

This is the default runtime. It is the recommended runtime for all new Java projects

实践总结

1. 代码量少很多。一行流式代码即可完成,无需臃肿的example用法

2. 0 XML,再也不用和XML打交道

  • 不存在XML的SQL注入风险。Fortify安全扫描中,再也不会被安全漏洞所困扰;
  • 不存在重构风险。过去重构代码时,IDE会忽略掉XML中的对应信息,导致重构不完整,出现软件错误;新的方式全基于JAVA,IDE重构完整;
  • 不存在自定义的mapper函数难以找到XML内定义SQL问题。原来需要手动去XML查找,无法借IDE之力。新的方式由于全基于JAVA,IDE可以直接找到自定义的SQL
  • 不存在自定义SQL的语法错问题。原来XML的方式是手写SQL,且需要填jdbcType,列信息等繁琐配置,且无法避免错误语法问题。新的方式基于JAVA API,不存在手写SQL导致的潜在语法问题。
  • 少了额外的XML,生成的文件更少,让注意力更聚焦;

3. 比基于XML生成的example系列通用函数更全

  • 终于具备非常常用的批量插入了(insertMultiple)
  • 也可以直接使用万能的select函数了(不再担心XML的selectByExample函数涉及安全风险,而不敢生成,导致简单的select函数都要自定义的搞笑事情)

4. 自定义的mapper可以继承通用mapper。原来XML的方式,自定义的mapper和生成的通用mapper是2个独立的接口,无法使用继承,否则会出现多个bean的错误。新的方式,自定义mapper可以继承生成的通用mapper,全局只需要一个自定义的mapper的bean即可。

代码对比

通用场景
旧的基于XML的Criteria模式
        SparringWorkflowNodeEntityExample example = new SparringWorkflowNodeEntityExample();
        SparringWorkflowNodeEntityExample.Criteria criteria = example.createCriteria();
        criteria.andDeleteFlagEqualTo(0);
        criteria.andWorkflowIdEqualTo(lessonId);
        example.setOrderByClause("sequence_number ASC");
        List<SparringWorkflowNode> workflowNodeEntities = sparringWorkflowNodeEntityMapper.selectByExample(example);

新的基于JAVA API的流式模式
List<SparringWorkflowNode> workflowNodeEntities = sparringWorkflowNodeMapper.select(c->c.where(deleteFlag, isEqualTo(0)).and(workflowId, isEqualTo(lessonId)).orderBy(sequenceNumber));

实践细节

MBG的配置文件

generator-configuration.xml这个文件,targetRuntime="MyBatis3DynamicSql" 这是最关键的配置,决定了这是基于JAVA API的Dynamic SQL的方式。

通用Mapper

自定义Mapper

对于无法使用通用mapper的场景,可以使用自定义的方式。

自定义一个接口,继承通用mapper(这样可以无需使用2个bean)

@Mapper
public interface SparringWorkflowMapperCustomized extends SparringWorkflowMapper {
    @TimeIt
    @SelectProvider(value = WorkflowSqlBuilder.class, method = "searchWorkflowVectorSimple")
    List<SparringWorkflow> searchWorkflowSimple(String query, ESparringWorkflowType workflowType, String account);

    @SelectProvider(value = WorkflowSqlBuilder.class, method = "getStudentAllLessons")
    List<SparringWorkflow> getStudentAllLessons(ESparringWorkflowType workflowType, String account);

}

通过Mybatis的JAVA API 定义SQL (可以参考Mybatis 官方 mybatis – MyBatis 3 | SQL 语句构建器

@Slf4j
public class WorkflowSqlBuilder {
    final static String TABLE_NAME = "sparring_workflow";
    final static String WEIGHT_VECTOR = "(setweight(to_tsvector('zh', workflow_name), 'A') ||  setweight(to_tsvector('zh', workflow_desc), 'C'))";
    public static String searchWorkflowVectorSimple(final String query, final ESparringWorkflowType workflowType, final String account){
        return new SQL(){{
            SELECT(" * ");
            FROM(String.format("%s, websearch_to_tsquery('zh', #{query}) search, ts_rank_cd(%s, search, 1) rank", TABLE_NAME, WEIGHT_VECTOR));
            WHERE(WEIGHT_VECTOR + " @@ search");
            WHERE("delete_flag = 0");
            if(workflowType != null){
                WHERE("workflow_type = #{workflowType.code}");  //mybatis会寻找code这个field的getter,实际执行的是workflowType.getCode()
            }
            /*
            在sql中,jsonb后面只有一个?,但是由于mybatis也使用?作为未知参数,会出现错误。因此,这里采用??等价sql里的?
             */
            if(Strings.isNotBlank(account)){
                WHERE("users::jsonb??#{account}");
            }
            ORDER_BY("rank DESC");
        }}.toString();
    }

    public static String getStudentAllLessons(final ESparringWorkflowType workflowType, final String account){
        return new SQL(){{
            SELECT("*");
            FROM(TABLE_NAME);
            WHERE("delete_flag = 0");
            if(workflowType != null){
                WHERE("workflow_type=#{workflowType.code}");
            }
            if(Strings.isNotBlank(account)){
                WHERE("users::jsonb??#{account}");
            }
            ORDER_BY("updated_date DESC");

        }}.toString();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值