【问题标题】:like-statement causes Unsupported query on Ignite 2.7 with QueryDSLlike-statement 导致在 Ignite 2.7 上使用 QueryDSL 进行不支持的查询
【发布时间】:2019-08-12 11:43:37
【问题描述】:

在 Spring Boot 应用程序中,我们使用 queryDSL 来访问数据库。应用程序应打印匹配(用户输入依赖)搜索参数的表中的所有项目。

例子:

  • 给我所有名称与“柏林”完全匹配的地点
  • 给我所有名称以“Ber”开头的位置。

所以我们必须动态创建 where 子句。

我们使用像这样的实体类

package example;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "location")
public class LocationEntity {

    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    public LocationEntity() {
        // -
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

类似的查询类

package example;

import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.StringPath;

public class QLocationEntity extends EntityPathBase<LocationEntity> {
    private static final long serialVersionUID = 1L;

    public static final QLocationEntity DEFAULT = new QLocationEntity("loc_1");

    public final NumberPath<Long> id = createNumber("id", Long.class);

    public final StringPath name = createString("name");

    public QLocationEntity(String tableAlias) {
        super(LocationEntity.class, tableAlias);
    }
}

类似的存储库类

package example;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface LocationRepository extends JpaRepository<LocationEntity, Long>,
        /* needed for query DSL. */
        QuerydslPredicateExecutor<LocationEntity> {
    /*
     * We don't need custom methods.
     */
}

还有一个小助手类,比如

package example;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;

@Service
public class LocationRepositoryHelper {
    protected final Log LOG = LogFactory.getLog(getClass());

    @Autowired
    private LocationRepository repository;

    public Sort sort = new Sort(Sort.Direction.ASC, "name");

    public Iterable<LocationEntity> findEntities(String paramLocation, boolean autocomplete)
            throws RequestParameterInvalideException {
        Predicate p = generatePredicate(paramLocation, autocomplete);
        if (p != null) {
            return repository.findAll(p, sort);
        } else {
            return repository.findAll(sort);
        }
    }

    BooleanExpression generatePredicate(String location, boolean autocomplete) {
        if ("".equals(location.trim())) {
            return null;
        } else if (autocomplete) {
            return QLocationEntity.DEFAULT.name.startsWith(location);
        } else {
            return QLocationEntity.DEFAULT.name.eq(location);
        }
    }
}

(这个例子远没有我们真正的应用程序代码复杂,但应该足以证明我们的问题。)

我们的应用程序向助手类请求一个列表,而 Spring Boot 应该通过巫术魔法完成其余的工作。

当我们使用 oracle 数据库作为 rdbms 时,一切都很好。当我们使用 ignite 时,只要我们不尝试使用 'autocompletion',一切都很好。

当我们尝试“自动完成搜索字符串”时,我们会得到一个 IgniteException,上面写着:不支持的查询:locationen0_.name like ?1 ESCAPE '!'

我们记录了以下 sql 字符串:

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name like ? escape '!' order by locationen0_.name asc

我们假设“?”必须替换为“Ber%”,所以完全限定的sql语句应该是:

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name like 'Ber%' escape '!' order by locationen0_.name asc;

我们在 Oracle DB (12.*) 和 Ignite (2.7) 上的 SQL 控制台中手动运行此语句。在 Oracle 上一切都很好,Ignite 仍然宣布我们会遇到语法错误/不支持的查询。 所以我们在 Ignite 上尝试了一些替代方案...

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name = 'Berlin' order by locationen0_.name asc;
=> all fine, but doesn't return what we want.

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name like 'Berlin' order by locationen0_.name asc;
=> all fine, but still doesn't return what we want.

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name = 'Ber%' order by locationen0_.name asc;
=> still all fine and would return what we want.

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name = 'Berlin' escape '!' order by locationen0_.name asc;
=> all fine (woot??), but wouldn't return what we want.

select locationen0_.id as id1_0_, locationen0_.name as name2_0_ from my_location locationen0_ where locationen0_.name = 'Ber%' escape '!' order by locationen0_.name asc;
=> (the original statement) unsupported query, but is what queryDSL (supposedly) generates and what should return what we want.

我们的第一个结论是:

  1. Ignite 知道 ESCAPE 关键字;使用关键字并不是在所有情况下都会导致问题。
  2. Ignite 可以理解内部带有“%”的类似语句。
  3. Ignite 不接受内含“%”和转义关键字的类似语句。

经过几个小时的分析,我们现在知道“导致问题的原因”,但我们不知道为什么这是一个问题。 queryDSL 框架(4.2.1 版)附加了硬编码的转义关键字,所以我们不知道如何抑制它。 切换到另一个框架可能是一种选择,尽管我们希望避免重构。 转储框架并“通过字符串连接构建语句”是可行的,但对于生产代码来说是没有选择的。

所以我们的问题是: 有没有人使用 queryDSL 和 Ignite 并且没有这个问题? 如果是这样,您是否以与我们完全不同的方式使用 queryDSL? (我们是否以“它不应该被使用”的方式使用 queryDSL?) 或者您知道解决问题的 Ignite 配置选项吗? 其他人有提示吗?

【问题讨论】:

    标签: java spring-boot sql-like ignite querydsl


    【解决方案1】:

    我研究了来源,结果发现 Ignite 明确禁止 ESCAPE。我们检查是否提供了 ESCAPE,如果提供了则指示错误。

    我认为您可以针对 Apache Ignite JIRA 提出问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 2013-03-29
      • 2020-09-30
      相关资源
      最近更新 更多