解决 Halo 默认数据库 H2 搜索大小写敏感的问题

Halo 默认使用 H2 作为数据库,在使用的时候碰到了一个问题,搜索 linux 结果搜不出来 Linux。这就很郁闷了,如果不解决这个问题,那么在搜索自己的笔记的时候搜索结果会不准,下面便是解决方案。

写这篇文章的时候使用 Halo 是 1.2.0 的版本,下文基于这个版本来分析。

Halo 在搜索时使用的方案是使用数据库中的 like 字段来实现搜索,通过在关键字的前后加 % 来实现搜索的效果。所以解决方案便是将搜索的列换成大小写不敏感的列即可。

以下代码是 Halo 拼接 sql 部分的代码(Halo 的源码托管在 github 上面,地址是: https://github.com/halo-dev/halo,有兴趣的同学可以下载下来自己查看)

// run.halo.app.service.impl.PostServiceImpl.java

    private Specification<Post> buildSpecByQuery(@NonNull PostQuery postQuery) {
        return (Specification<Post>) (root, query, criteriaBuilder) -> {
            ...
            if (postQuery.getKeyword() != null) {
                // 拼接关键字的地方
                String likeCondition = String.format("%%%s%%", StringUtils.strip(postQuery.getKeyword()));

                // 可以看到,下面便是拼接查询的 sql
                // 其中查询两个字段,一个是 title,另一个是 originalContent
                Predicate titleLike = criteriaBuilder.like(root.get("title"), likeCondition);
                Predicate originalContentLike = criteriaBuilder.like(root.get("originalContent"), likeCondition);

                predicates.add(criteriaBuilder.or(titleLike, originalContentLike));
            }

            return query.where(predicates.toArray(new Predicate[0])).getRestriction();
        };
    }

在 H2 中,有一个 VARCHAR_IGNORECASE 数据结构,它是忽略大小写的可变字符串,我们把 POSTS 表的 titleoriginalContent 字段换成 VARCHAR_IGNORECASE 类型即可解决这个问题。

如果要远程访问 H2 数据库,那么需要先将远程的 H2 访问权限打开,通过在 application.ymal 文件中增加下面的配置来打开远程访问。

spring:
  h2:
    console:
      settings:
        web-allow-others: true
      path: /h2-console
      enabled: true

配置好之后重启服务,然后访问 http://<host:ip>/h2-console 即可访问到 H2 提供的 Web 界面。

H2 提供的 Web 连接界面

然后在其中配置我们服务器上配置的 JDBC URLUser NamePassword。配置好之后点击 Connect 进行连接。进去之后的界面如下所示。

H2 提供的控制台

我们需要修改的表便是 POSTS 表,接下来输入下面两句 SQL 修改数据类型即可。

alter table POSTS alter TITLE set data type VARCHAR_IGNORECASE;
alter table POSTS alter ORIGINAL_CONTENT set data type VARCHAR_IGNORECASE;

到这一步便完成了替换数据类型的操作,接下来还有一步非常重要的操作。就是关闭 H2 的远程访问,不然被别人爆破了数据库就完了。下面将 application.ymal 文件中的 H2 配置改成下面的样子然后重启服务即可。

spring:
  h2:
    console:
      settings:
        web-allow-others: true
      path: /h2-console
      enabled: false

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: /2020/03/12/f8119efb5bf27ad64d17fd5a675a6dc3c80452e76ce5743154620118ab7c947a