当前位置: 首页 > 面试题库 >

使用hibernate标准,是否可以转义特殊字符?

吴胜
2023-03-14
问题内容

对于此问题,我们希望避免编写特殊查询,因为该查询在多个数据库中必须有所不同。仅希望使用hibernate条件,我们希望能够转义特殊字符。

这种情况是需要转义特殊字符的原因:

假设我们在数据库中有表“ foo”。表’foo’仅包含1个字段,称为’name’。“名称”字段可以包含在数据库中可能被认为是特殊字符。此名称的两个示例是“
name_1”和“ name%1”。至少在Oracle中,“
_”和“%”都是特殊字符。如果用户想要在将这些示例输入数据库后搜索其中一个示例,则可能会出现问题。

criterion = Restrictions.ilike("name", searchValue, MatchMode.ANYWHERE);
return findByCriteria(null, criterion);

在此代码中,“ searchValue”是用户已授予应用程序用于其搜索的值。如果用户要搜索“%”,则将返回数据库中的每个“
foo”条目。这是因为’%’字符表示用于字符串匹配的“任意数量的字符”通配符,并且hibernate生成的SQL代码如下所示:

select * from foo where name like '%'

有没有办法告诉hibernate的转义某些字符,或创建不是数据库类型特定的解决方法?


问题答案:

LikeExpression的构造函数均受保护,因此这不是一个可行的选择。同样,它也有自己的问题。

我和一位同事创建了一个效果很好的补丁。补丁的要点是,对于使用MatchMode的LikeExpression构造函数,我们转义了特殊字符。对于使用Character(转义字符)的构造函数,我们假设用户自己转义了特殊字符。

我们还参数化了转义字符,以确保它们使用\或引号字符之类的字符时不会破坏SQL查询。

package org.hibernate.criterion;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.TypedValue;

public class LikeExpression implements Criterion {
    private final String propertyName;
    private final String value;
    private final Character escapeChar;

    protected LikeExpression(
            String propertyName,
            Object value) {
        this(propertyName, value.toString(), (Character) null);
    }

    protected LikeExpression(
            String propertyName,
            String value,
            MatchMode matchMode) {
        this( propertyName, matchMode.toMatchString( value
                .toString()
                .replaceAll("!", "!!")
                .replaceAll("%", "!%")
                .replaceAll("_", "!_")), '!' );
    }

    protected LikeExpression(
            String propertyName,
            String value,
            Character escapeChar) {
        this.propertyName = propertyName;
        this.value = value;
        this.escapeChar = escapeChar;
    }

    public String toSqlString(
            Criteria criteria,
            CriteriaQuery criteriaQuery) throws HibernateException {
        Dialect dialect = criteriaQuery.getFactory().getDialect();
        String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, propertyName );
        if ( columns.length != 1 ) {
            throw new HibernateException( "Like may only be used with single-column properties" );
        }
        String lhs = lhs(dialect, columns[0]);
        return lhs + " like ?" + ( escapeChar == null ? "" : " escape ?" );

    }

    public TypedValue[] getTypedValues(
            Criteria criteria,
            CriteriaQuery criteriaQuery) throws HibernateException {
        return new TypedValue[] {
                criteriaQuery.getTypedValue( criteria, propertyName, typedValue(value) ),
                criteriaQuery.getTypedValue( criteria, propertyName, escapeChar.toString() )
        };
    }

    protected String lhs(Dialect dialect, String column) {
        return column;
    }

    protected String typedValue(String value) {
        return value;
    }

}

如果您想知道lhs和typedValue方法的用途,新的IlikeExpression应该回答这些问题。

package org.hibernate.criterion;

import org.hibernate.dialect.Dialect;

public class IlikeExpression extends LikeExpression {

    protected IlikeExpression(
            String propertyName,
            Object value) {
        super(propertyName, value);
    }

    protected IlikeExpression(
            String propertyName,
            String value,
            MatchMode matchMode) {
        super(propertyName, value, matchMode);

    }

    protected IlikeExpression(
            String propertyName,
            String value,
            Character escapeChar) {
        super(propertyName, value, escapeChar);
    }

    @Override
    protected String lhs(Dialect dialect, String column) {
        return dialect.getLowercaseFunction() + '(' + column + ')';
    }

    @Override
    protected String typedValue(String value) {
        return super.typedValue(value).toLowerCase();
    }

}

此后,剩下的唯一事情就是使Restrictions使用以下新类:

public static Criterion like(String propertyName, Object value) {
    return new LikeExpression(propertyName, value);
}

public static Criterion like(String propertyName, String value, MatchMode matchMode) {
    return new LikeExpression(propertyName, value, matchMode);
}

public static Criterion like(String propertyName, String value, Character escapeChar) {
    return new LikeExpression(propertyName, value, escapeChar);
}

public static Criterion ilike(String propertyName, Object value) {
    return new IlikeExpression(propertyName, value);
}

public static Criterion ilike(String propertyName, String value, MatchMode matchMode) {
    return new IlikeExpression(propertyName, value, matchMode);
}

public static Criterion ilike(String propertyName, String value, Character escapeChar) {
    return new IlikeExpression(propertyName, value, escapeChar);
}

编辑:哦,是的。这适用于Oracle。但是,我们不确定其他数据库。



 类似资料:
  • 问题内容: 对于此问题,我们希望避免编写特殊查询,因为该查询在多个数据库中必须有所不同。仅希望使用休眠条件,我们希望能够转义特殊字符。 这种情况是需要转义特殊字符的原因: 假设我们在数据库中有表’foo’。表’foo’仅包含1个字段,称为’name’。“名称”字段可以包含在数据库中可能被认为是特殊字符。此名称的两个示例是“ name_1”和“ name%1”。至少在Oracle中,“ _”和“%”

  • 正如我们所看到的,一个反斜杠 "\" 是用来表示匹配字符类的。所以它是一个特殊字符。 还存在其它的特殊字符,这些字符在正则表达式中有特殊的含义。它们可以被用来做更加强大的搜索。 这里是包含所有特殊字符的列表:[ \ ^ $ . | ? * + ( )。 现在并不需要尝试去记住它们 —— 当我们分别处理其中的每一个时,你自然而然就会记住它们。 转义 如果要把特殊字符作为常规字符来使用,只需要在它前面

  • 我在datasource password字段中有特殊字符,如“(双引号)、@,~,!,%,&,},”。当我运行springboot应用程序时,当它试图连接到我遇到的数据库时- 我的问题是: (1)是否有方法查看Spring尝试连接时使用的密码? (2)是否需要转义中密码中的任何特殊字符? 我能够使用一个独立的java程序连接到数据库,但是我必须转义密码中的双引号。我在后端使用了SpringBoo

  • 问题内容: 我想通过javascript函数将文本显示为HTML。如何在JS中转义html特殊字符?是否有API? 问题答案:

  • 问题内容: 我想电视机1 ® 2的outputText: 什么不对?我大写。 问题答案: 您可以选择以下之一 在您最初的建议中,您放错了位置,应该在 您也可以完全删除(但您的(R)不会很小) 最后,您可以直接使用它而无需转义

  • 问题内容: 我正在使用NEST与我的应用程序中的Elasticsearch通信。 在这种情况下,用户输入返回正确结果的搜索词。但是,如果他们搜索查询或结果不回来。 我以为这是由于特殊字符引起的,所以我尝试对它们进行转义-但随后也没有结果返回。我的查询正确吗,我做错了吗? 此外, 我在转义查询的末尾附加了通配符以匹配任何开放式末尾。 搜索方式: 转义方法: 我很乐意提供任何帮助或指示,以了解为什么这