如何使用SpringBoot + JPA存储PostgreSQL jsonb?

Mag*_*o C 3 postgresql spring-data-jpa spring-boot jsonb

我正在开发一种迁移软件,它将使用来自REST服务的未知数据.

我已经考虑过使用MongoDB,但我决定不使用它并使用PostgreSQL.

阅读本文之后,我尝试使用Spring JPA在我的SpringBoot应用程序中实现它,但我不知道jsonb在我的实体中进行映射.

试过这个,但什么都不懂!

我就是这样的地方:

@Repository
@Transactional
public interface DnitRepository extends JpaRepository<Dnit, Long> {

    @Query(value = "insert into dnit(id,data) VALUES (:id,:data)", nativeQuery = true)
    void insertdata( @Param("id")Integer id,@Param("data") String data );

}
Run Code Online (Sandbox Code Playgroud)

和......

@RestController
public class TestController {

    @Autowired
    DnitRepository dnitRepository;  

    @RequestMapping(value = "/dnit", method = RequestMethod.GET)
    public String testBig() {
        dnitRepository.insertdata(2, someJsonDataAsString );
    }

}
Run Code Online (Sandbox Code Playgroud)

和表:

CREATE TABLE public.dnit
(
    id integer NOT NULL,
    data jsonb,
    CONSTRAINT dnit_pkey PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

注意:我不希望/需要实体来处理.我的JSON将永远是String但我需要jsonb来查询数据库

Cep*_*pr0 16

试过这个,但什么都不懂!

要具有完全工作jsonb春季数据JPA(休眠)与弗拉德·米哈尔西亚的项目休眠类型的lib你应该做到以下几点:

1)将此lib添加到您的项目中:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.2.2</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

2)然后在您的实体中使用其类型,例如:

@Data
@NoArgsConstructor
@Entity
@Table(name = "parents")
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
public class Parent implements Serializable {

    @Id
    @GeneratedValue(strategy = SEQUENCE)
    private Integer id;

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

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private List<Child> children;

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private Bio bio;

    public Parent(String name, List children, Bio bio) {
        this.name = name;
        this.children = children;
        this.bio = bio;
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Child implements Serializable {
    private String name;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Bio implements Serializable {
    private String text;
}
Run Code Online (Sandbox Code Playgroud)

然后,您将能够使用,例如,使用简单JpaRepository的对象:

public interface ParentRepo extends JpaRepository<Parent, Integer> {
}
Run Code Online (Sandbox Code Playgroud)
parentRepo.save(new Parent(
                     "parent1", 
                     asList(new Child("child1"), new Child("child2")), 
                     new Bio("bio1")
                )
);
Run Code Online (Sandbox Code Playgroud)
Parent result = parentRepo.findById(1);
List<Child> children = result.getChildren();
Bio bio = result.getBio();
Run Code Online (Sandbox Code Playgroud)

  • @MagnoC我的答案不是解决方案.这只是'hibernate-types'的帮助;) (4认同)
  • 如果这个世界上没有vlad我们该怎么办? (3认同)

use*_*367 14

已经有几个答案,我很确定它们适用于多种情况。我不想再使用任何我不知道的依赖项,所以我寻找另一个解决方案。重要的部分是AttributeConverter,它将 jsonb 从数据库映射到您的对象,反之亦然。因此,您必须使用@Convert注释实体中 jsonb 列的属性,并链接AttributeConverter并添加@Column(columnDefinition = "jsonb"),以便 JPA 知道这在数据库中是什么类型。这应该已经可以启动 Spring Boot 应用程序了。但是,每当您尝试使用JpaRepository进行save()时,您都会遇到问题。我收到消息:

PSQLException:错误:列“myColumn”的类型为 jsonb,但表达式的类型为字符变化。

提示:您需要重写或转换表达式。

发生这种情况是因为 postgres 对类型的处理有点过于严肃。您可以通过更改配置来解决此问题:

datasource.hikari.data-source-properties:stringtype =未指定

datasource.tomcat.connection-properties:stringtype=未指定

后来它对我来说就像一个魅力,这是一个最小的例子。我使用 JpaRepositories:

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

@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Integer> {
}
Run Code Online (Sandbox Code Playgroud)

实体:

import javax.persistence.Column;
import javax.persistence.Convert;

public class MyEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  protected Integer id;

  @Convert(converter = MyConverter.class)
  @Column(columnDefinition = "jsonb")
  private MyJsonObject jsonContent;

}
Run Code Online (Sandbox Code Playgroud)

json 的模型:

public class MyJsonObject {

  protected String name;

  protected int age;

}
Run Code Online (Sandbox Code Playgroud)

转换器,我这里使用 Gson,但是你可以按照你喜欢的方式映射它:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class MyConverter implements AttributeConverter<MyJsonObject, String> {

  private final static Gson GSON = new Gson();

  @Override
  public String convertToDatabaseColumn(MyJsonObject mjo) {
    return GSON.toJson(mjo);
  }

  @Override
  public MyJsonObject convertToEntityAttribute(String dbData) {
    return GSON.fromJson(dbData, MyJsonObject.class);
  }
}
Run Code Online (Sandbox Code Playgroud)

SQL:

create table my_entity
(
    id serial primary key,
    json_content jsonb

);
Run Code Online (Sandbox Code Playgroud)

和我的 application.yml (application.properties)

  datasource:
    hikari:
      data-source-properties: stringtype=unspecified
    tomcat:
      connection-properties: stringtype=unspecified
Run Code Online (Sandbox Code Playgroud)


M. *_*num 9

通过添加 Spring Data JPA 只是为了执行简单的插入语句,您使事情变得过于复杂。您没有使用任何 JPA 功能。而是执行以下操作

  1. 替换spring-boot-starter-data-jpaspring-boot-starter-jdbc
  2. 删除您的DnitRepository界面
  3. 进样JdbcTemplate,你在那里注射DnitRepository
  4. 替换dnitRepository.insertdata(2, someJsonDataAsString );jdbcTemplate.executeUpdate("insert into dnit(id, data) VALUES (?,to_json(?))", id, data);

您已经在使用普通 SQL(以一种非常复杂的方式),如果您需要普通 SQL(并且不需要 JPA),那么只需使用 SQL。

当然,不是直接将 注入JdbcTemplate到您的控制器中,您可能希望在存储库或服务中隐藏该逻辑/复杂性。

  • 好复杂,因为试图将它硬塞进 JPA 而不实际使用 JPA 并使用您不需要的层。 (3认同)