【问题标题】:How to query with Spring JPA on jsonb columns?如何在 jsonb 列上使用 Spring JPA 进行查询?
【发布时间】:2020-01-13 23:47:02
【问题描述】:

我正在使用 Spring JPA 和 PostgreSQL 数据库。我有一个实体如下:

@Entity
@TypeDef(name="json_binary", typeClass = com.vladmihalcea.hibernate.type.json.JsonBinaryType.class)
public class LiveTokens {

   @Id
   @GeneratedValue()
   private Long id;

   private String username;

   @Type(type="json_binary")
   @Column(columnDefinition = "jsonb")
   private Token token
}

Token:

public class Token {
   private Long expireTime;
   private String accessToken;
}

为了使用 Hibernate 将对象保存到列,我使用 Hibernate Types 项目。 现在我想获取所有过期的LiveTokens。我不能用 Spring JPA 做到这一点。如何使用 Spring data JPA 查询 posgresql jsonb 列?

【问题讨论】:

    标签: java spring postgresql hibernate spring-data-jpa


    【解决方案1】:

    SQL JSON 函数

    如果你想调用一个处理 JSON 列的 SQL 函数,那么你只需要在使用 Hibernate 之前确保你register the function

    JSON 运算符

    对于 JSON 运算符,例如 PostgreSQL 运算符(例如,->>),您唯一的选择是使用原生 SQL 查询。 JPQL 或 HQL 不支持特定于数据库的 JSON 运算符。

    【讨论】:

      【解决方案2】:

      使用 EclipseLink 和 spring data jpa,如果您在 db 中的数据类似于:{"expireTime":102020230201, "accessToken":"SOMETHING" },我的第一个问题是为什么要为您的日期使用长数字而不是时间戳(例如'2019-09-14 12:05:00')。如果您使用时间戳,还可以选择管理时区(来自 postgresql 或来自您的源代码)。
      关于您的问题,您可以使用FUNC JPQL keyword of EclipseLink(Hibernate 可能有类似的东西)来运行特定于数据库的功能。在下面的示例中,我使用 FUNC('jsonb_extract_path_text', lt.token, 'expireTime') 来获取 token.expireTime 的 json 值。
      PostgreSql 方法jsonb_extract_path_text 返回文本,因此你不能做更少的条件,所以我使用JPQL CAST keyword(CAST -data- TO -type-) 转换函数的输出。

      @Repository
      public interface MyRepository extends JpaRepository<LiveTokens, Integer> {
      
          @Query(value = "SELECT lt FROM LiveTokens lt WHERE CAST(FUNC('jsonb_extract_path_text', lt.token, 'expireTime') AS LongType) < :expirirationThreshold")
          List<LiveTokens> findByExpireTime(@Param("expirirationThreshold") Long expirirationThreshold);
      }
      

      同样,这未经测试。

      【讨论】:

      • 这个错误Could not resolve requested type for CAST : int8[select lt from ...]
      • 你得到的错误是关于 INT8 类型的 CAST 使用。您可以将 INT8 替换为其他类型。你也可以试试 LongType 或 Long。
      【解决方案3】:

      这是使用 postgres JSON 查询运算符的本机查询的样子,结合您的示例:

      @Query(value="SELECT t.* FROM LiveTokens t WHERE CAST(t.token ->> 'expireTime' AS LONG) < now()", native=true)
      

      假设您的 real 表名是 LiveTokens,本机查询不再使用 JPA 转换,并且表名必须与数据库中的表名匹配。 (您可能还需要指定它的架构。)

      【讨论】:

        【解决方案4】:

        试试看:

        服务类:

        Long currentTime = new Date().getTime();
        

        存储库:

        @Query("SELECT lt FROM LiveTokens lt WHERE lt.token.expireTime <= :currentTime")
        
        List<LiveTokens> findExpiredLiveTokens(@Param("currentTime") long currentTime)
        

        【讨论】:

          猜你喜欢
          • 2017-10-09
          • 1970-01-01
          • 2018-05-31
          • 2017-07-28
          • 2017-08-21
          • 2018-12-14
          • 1970-01-01
          • 2012-07-25
          • 1970-01-01
          相关资源
          最近更新 更多