Postgres中不区分大小写

时间:2014-08-21 17:21:47

标签: java hibernate postgresql jpa case-insensitive

我目前正在做一个已经开发了几个月的Java项目。该项目已基本完成,现在我意识到Postgres是一个区分大小写的。

在我的登录过程中,它无法区分username和“UserName”。我使用Java base,Hibernate和JPA作为后端实现,并使用Postgres作为数据库。

我一直在网上搜索解决方案,我得到的大部分答案都建议我使用解决方案:

select loginId from user where 
lower(loginId)=loginid.toLowerCase();

或将表列的数据类型更改为citext。

但有没有更快的方法呢?或者Postgres.conf中是否有任何变量可以控制不区分大小写?或者在休眠状态下我能轻松控制它吗?

我知道使用方法lower(loginId)=loginId.toLowerCase()是解决问题的最简单方法,但我需要在项目中更改很多代码,这可能需要很长时间才能解决。将数据类型更改为citext对于很久以前实现的项目来说并不是一个很好的解决方案。

这里有人有更好的解决方案来修复我当前的问题吗?

3 个答案:

答案 0 :(得分:4)

PostgreSQL has no case-insentitive collations,全局或基于每列/运算符。它也没有"区分大小写"配置选项。

您的选择是:

  • 在需要大小写的cols上使用citext类型。如果列始终不区分大小写,则可能是最佳选择;这就是我要做的,除非Hibernate有问题。重要的是,citext 不区分大小写保留,即保留大写字母,它们在比较中并不重要。

  • 明确比较每个lower(col) = lower('Literal')的较低值的值。无法在col上使用索引,您必须在lower(col)上创建单独的索引。 col上的唯一约束(包括主键)不会不区分大小写;如果你想要这个,你必须在lower(col)上创建一个唯一索引。这种方法是保留大小的。

  • CHECK上添加col约束,该约束仅允许使用小写值并拒绝大写值。您可以将其与BEFORE INSERT OR UPDATE ... FOR EACH ROW触发器结合使用,如果需要,可以使用小写输入。这样,列的值只能是小写的。然后,您只需确保客户端应用程序始终使用小写值进行比较。这种方法不是保留大小的 - 当您输入BOB时,数据库会存储bob,并且以后无法知道哪个是输入。

  • 由于您正在使用ORM,因此您可以在模型代码中执行下限。只需让您的实体在访问器上始终toLowerCase输入和输出。您仍然需要记住在代码中小写比较的其他方面值,但它不那么脆弱。同样,这不是保留案例的。

就个人而言,我只是在适当的地方使用citext,这就是它的用途。

只有在initdb时才可以在PostgreSQL中进行区分大小写的全局切换 - 否则打开或关闭区分大小写将突然使先前有效的唯一约束被违反,以前有效的外键约束被违反,中断检查约束,它也违反了SQL标准,这需要区分大小写的操作。所以PostgreSQL不支持它。

有用的是,每列和每个运算符的排序规则是否覆盖支持的不区分大小写的排序规则。但是,他们没有。

答案 1 :(得分:0)

你可以尝试一下,看看它是否适合你。我建议您将其用作临时工具,直到修复程序为止。

SELECT loginID 
FROM user 
WHERE (SELECT CHAR_LENGTH(REGEXP_REPLACE(loginId,*loginId from java*,'','ig')) = 0)

如果loginID匹配,则应该为您提供loginID,而不检查区分大小写。此外,如果您有多个相同的登录但不同的情况,那么这将不适合您。

以下是使用我的数据库中的一个测试表的输出示例。用户名在我的表中都是大写的。

select username from test.person where (select char_length(regexp_replace(username,'jMeRlOs','', 'ig')) = 0)

结果:enter image description here

答案 2 :(得分:0)

你有正确的想法,你只需要在lower(loginId)上使用基于表达式的索引。参见

http://www.postgresql.org/docs/9.1/static/indexes-expressional.html

有关基于表达式的索引的详细信息。在您的情况下,您将要创建:

CREATE INDEX tablename_lower_loginId_idx ON tablename(lower(loginId));

如果您已经有不能执行此操作的代码,则可以重命名表并创建视图。然后您的代码将从您的视图中读取,但您仍然需要更改您写入的表的名称。

还有一点需要注意:对于loginId,最好只在第一个位置存储小写值,如另一个答案所述。也许您可以创建一个新列,并将所有小写的loginId复制到新列中,然后设置一个约束以确保没有新的无效条目进入。然后用新列替换旧列并确保你只能将较低价值的值传递给你的后端。