HQL turn SQL

Scenarios

Among the current system is a distributed micro-services, among A system using Hibernate, in which B Spring JDBCTemplate system is well known, these two data query language lasting framework uses a completely different, though Hibernate is using SQL direct inquiries, of course, some students will think of using Hibernate multi-database to solve, because the actual production can not be described when there reason not to do so, there will be students said use Hibernate directly convertible but this approach requires the object must be managed in Hibernate available to achieve the conversion, this mission which is managed Hibernate ORM does not exist.

@Override
    public String doHqlToSql(String hqlQueryText) {
        QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory();
        Session session = entityManager.unwrap(Session.class);
        SessionFactoryImplementor factory = (SessionFactoryImplementor) session.getSessionFactory();
        QueryTranslator translator = translatorFactory.createQueryTranslator(hqlQueryText, hqlQueryText, Collections.EMPTY_MAP, factory,null);
        translator.compile(Collections.EMPTY_MAP, false);
        return translator.getSQLString();
    }

In this scenario A system call query using B system is Cloud calling boast services, transport past is HQL However, among the B system requires a HQL turn SQL to perform, nonsense too long-winded for a long time you small partners is already patience for a long time it! Ha ha ha look at code ~!

Solution


    /**
     * HQL 转 SQL
     * <per>
     *     <br/> DEMO: "SELECT  sui.id AS sui_id, sui.name AS sui_name, sui.userEmpNo AS sui_userEmpNo, sui.organizeCode AS sui_organizeCode, sui.departmentNameRdd AS sui_departmentNameRdd, su.userPhone AS su_userPhone FROM  SysUserInfo AS sui left join SysUser AS su ON su.userInfoId = sui.id WHERE 1=1  AND sui.name LIKE :sui_name AND sui.userEmpNo LIKE :sui_userEmpNo"
     *     <br/> 根据 DEMO HQL 的特点可分析得出
     *     <br/>    1、HQL是对象的方式进行查询的,那么Java 当中对象的方式必然都是以 . 的方式调用,所以属性我们可以使用 . 关键字替换
     *     <br/>    2、对象必然都是在 FROM 值 WHERE 中间每个对象都是有相应的别名的,所以根据AS 做文章进行截取转换
     *     <br/> 实现逻辑:
     *     <br/>    属性更名: 根据 . 的位置找出需要替换的属性 然后转换 加入到行的 String当中
     *     <br/>    对象更名:
     *     <br/>        由于 AS  是在对象后面的那么我们需要对String 进行反向截取,同样需要先找出 AS 位置然后进行对象更名操作
     *     <br/>        最终在处理完成后需要String 顺序反转一次
     *     <br/> 注意事项:
     *     <br/>    未做处理HQL
     *     <br/>        SELECT FROM SysUser
     *     <br/>        FROM SysUser
     *     <br/>    HQL 必要条件
     *     <br/>        对象必须要有 AS
     * </per>
     * @param hql
     * @return sql
     */
    public static String getHqlToSQL(String hql){
        StringBuffer sql = new StringBuffer();
        if (StringUtils.isNotBlank(hql)) {
            char[] hqlCharArr = hql.toCharArray();
            int indexStart = -1;
            int indexEnd = -1;

            /**
             * 更改字段名称(实现原理)
             *  1、根据HQL 的特点 . 找出属性开始位置
             *  2、找出属性结束位置 ' '
             *  3、替换 属性名称
             */
            for (int i = 0; i < hqlCharArr.length; i++) {
                char letter = hqlCharArr[i];
                if (letter == '.') {    // 找出开始位置
                    indexStart = i;
                }

                if (indexStart != -1 && letter == ' ') { // 找出结束位置
                    indexEnd = i;
                }

                if (indexStart != -1 && indexEnd != -1) {       // 字符串替换
                    char[] replace = Arrays.copyOfRange(hqlCharArr, indexStart, indexEnd);
                    sql.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, new String(replace)));
                    indexStart = -1;
                    indexEnd = -1;
                }

                if (indexStart == -1) {
                    sql.append(letter);
                }
            }

            hqlCharArr = sql.toString().toCharArray();
            int fromIndex = sql.indexOf("FROM") + 4;
            int whereIndex = sql.indexOf("WHERE");
            int fromObjectEnd = -1;
            int fromObjectStart = -1;
            sql = new StringBuffer();

            /**
             * 更新对象名称(实现原理)
             *  1、HQL 的对象是在 FROM 至 WHERE 中间
             *  2、根据 AS 的位置找出 需要截取的 截止位置
             *  3、根据 ' ' 找出需要替换的开始位置
             *  4、替换 对象名称
             */
            for (int i = hqlCharArr.length - 1 ; i >= 0; i--) {
                char letter = hqlCharArr[i];

                if(i < whereIndex && i > fromIndex){
                    if(letter == 'S' && hqlCharArr[i - 1] == 'A'){
                        fromObjectEnd = i - 2;
                    }

                    if(fromObjectEnd != -1 && fromObjectEnd != i && letter == ' '){
                        fromObjectStart = i + 1;
                    }
                }

                if (fromObjectStart != -1 && fromObjectEnd != -1) {
                    char[] replace = Arrays.copyOfRange(hqlCharArr, fromObjectStart, fromObjectEnd);
                    sql.append(StringUtils.reverse(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,new String(replace))));
                    fromObjectStart = -1;
                    fromObjectEnd = -1;
                }

                if(fromObjectEnd == -1){
                    sql.append(letter);
                }
            }

        }
        return StringUtils.reverse(sql.toString());
    }

Reproduced in: https: //my.oschina.net/u/1265083/blog/3056470

Guess you like

Origin blog.csdn.net/weixin_33691700/article/details/92087607