how to store PostgreSQL jsonb using SpringBoot + JPA?

后端 未结 4 1690
不知归路
不知归路 2021-02-01 10:23

I\'m working on a migration software that will consume unknown data from REST services.

I already think about use MongoDB but I decide to not use it and use PostgreSQL.<

相关标签:
4条回答
  • 2021-02-01 10:43

    Tried this but understood nothing!

    To fully work with jsonb in Spring Data JPA (Hibernate) project with Vlad Mihalcea's hibernate-types lib you should just do the following:

    1) Add this lib to your project:

    <dependency>
        <groupId>com.vladmihalcea</groupId>
        <artifactId>hibernate-types-52</artifactId>
        <version>2.2.2</version>
    </dependency>
    

    2) Then use its types in your entities, for example:

    @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;
    }

    Then you will be able to use, for example, a simple JpaRepository to work with your objects:

    public interface ParentRepo extends JpaRepository<Parent, Integer> {
    }
    
    parentRepo.save(new Parent(
                         "parent1", 
                         asList(new Child("child1"), new Child("child2")), 
                         new Bio("bio1")
                    )
    );
    
    Parent result = parentRepo.findById(1);
    List<Child> children = result.getChildren();
    Bio bio = result.getBio();
    
    0 讨论(0)
  • 2021-02-01 10:54

    If you're using R2DBC you can use dependency io.r2dbc:r2dbc-postgresql, and use type io.r2dbc.postgresql.codec.Json in your member attributes of an entity class, e.g.:

    public class Rule {
        @Id
        private String client_id;
        private String username;
        private String password;
        private Json publish_acl;
        private Json subscribe_acl;
    }
    
    0 讨论(0)
  • 2021-02-01 10:58

    For this case, I use the above tailored converter class, you are free to add it in your library. It is working with the EclipseLink JPA Provider.

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.apache.log4j.Logger;
    import org.postgresql.util.PGobject;
    
    import javax.persistence.AttributeConverter;
    import javax.persistence.Converter;
    import java.io.IOException;
    import java.sql.SQLException;
    import java.util.Map;
    
    @Converter
    public final class PgJsonbToMapConverter implements AttributeConverter<Map<String, ? extends Object>, PGobject> {
    
        private static final Logger LOGGER = Logger.getLogger(PgJsonbToMapConverter.class);
        private static final ObjectMapper MAPPER = new ObjectMapper();
    
        @Override
        public PGobject convertToDatabaseColumn(Map<String, ? extends Object> map) {
            PGobject po = new PGobject();
            po.setType("jsonb");
    
            try {
                po.setValue(map == null ? null : MAPPER.writeValueAsString(map));
            } catch (SQLException | JsonProcessingException ex) {
                LOGGER.error("Cannot convert JsonObject to PGobject.");
                throw new IllegalStateException(ex);
            }
            return po;
        }
    
        @Override
        public Map<String, ? extends Object> convertToEntityAttribute(PGobject dbData) {
            if (dbData == null || dbData.getValue() == null) {
                return null;
            }
            try {
                return MAPPER.readValue(dbData.getValue(), new TypeReference<Map<String, Object>>() {
                });
            } catch (IOException ex) {
                LOGGER.error("Cannot convert JsonObject to PGobject.");
                return null;
            }
        }
    
    }
    

    Usage example, for an entity named Customer.

    @Entity
    @Table(schema = "web", name = "customer")
    public class Customer implements Serializable {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
    
        @Convert(converter = PgJsonbToMapConverter.class)
        private Map<String, String> info;
    
        public Customer() {
            this.id = null;
            this.info = null;
        }
    
        // Getters and setter omitted.
    
    0 讨论(0)
  • 2021-02-01 11:03

    You are making things overly complex by adding Spring Data JPA just to execute a simple insert statement. You aren't using any of the JPA features. Instead do the following

    1. Replace spring-boot-starter-data-jpa with spring-boot-starter-jdbc
    2. Remove your DnitRepository interface
    3. Inject JdbcTemplate where you where injecting DnitRepository
    4. Replace dnitRepository.insertdata(2, someJsonDataAsString ); with jdbcTemplate.executeUpdate("insert into dnit(id, data) VALUES (?,to_json(?))", id, data);

    You were already using plain SQL (in a very convoluted way), if you need plain SQL (and don't have need for JPA) then just use SQL.

    Ofcourse instead of directly injecting the JdbcTemplate into your controller you probably want to hide that logic/complexity in a repository or service.

    0 讨论(0)
提交回复
热议问题