如何使用JPA将map JSON列Map到Java对象

b5lpy0ml  于 2023-02-01  发布在  Java
关注(0)|答案(8)|浏览(219)

我们有一个包含许多列的大表。在我们移动到MySQL Cluster后,无法创建该表,原因是:
错误1118(42000):行大小太大。所用表类型的最大行大小为14000(不包括BLOB)。这包括存储开销,请查阅手册。您必须将某些列更改为TEXT或BLOB
例如:

@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
    @Id @Column (name = "id", nullable = false)
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int id;

    @OneToOne @JoinColumn (name = "app_id")
    private App app;

    @Column(name = "param_a")
    private ParamA parama;

    @Column(name = "param_b")
    private ParamB paramb;
}

这是一个存储配置参数的表,我在想我们可以将一些列合并成一个,并将其存储为JSON对象,然后将其转换为某个Java对象。
例如:

@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
    @Id @Column (name = "id", nullable = false)
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int id;

    @OneToOne @JoinColumn (name = "app_id")
    private App app;

    @Column(name = "params")
    //How to specify that this should be mapped to JSON object?
    private Params params;
}

其中我们定义:

public class Params implements Serializable
{
    private ParamA parama;
    private ParamB paramb;
}

通过使用这个,我们可以把所有的列合并成一个,创建我们的表。或者我们可以把整个表拆分成几个表。我个人更喜欢第一个解决方案。
无论如何,我的问题是如何MapParams列,它是文本,包含Java对象的JSON字符串?

xiozqbni

xiozqbni1#

您可以使用JPA转换器将您的实体Map到数据库,只需在params字段中添加一个类似下面的注解:

@Convert(converter = JpaConverterJson.class)

然后以类似的方式创建类(这将转换一个泛型Object,您可能需要将其专门化):

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

  private final static ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public String convertToDatabaseColumn(Object meta) {
    try {
      return objectMapper.writeValueAsString(meta);
    } catch (JsonProcessingException ex) {
      return null;
      // or throw an error
    }
  }

  @Override
  public Object convertToEntityAttribute(String dbData) {
    try {
      return objectMapper.readValue(dbData, Object.class);
    } catch (IOException ex) {
      // logger.error("Unexpected IOEx decoding json from database: " + dbData);
      return null;
    }
  }

}

就是这样:你可以使用这个类将表中的任何对象序列化为json。

rryofs0p

rryofs0p2#

JPAAttributeConverter在MapJSON对象类型方面受到太多限制,特别是当您希望将它们保存为JSON二进制文件时。
你不必创建一个自定义的Hibernate类型来获得JSON支持,你所需要做的就是使用Hibernate Types OSS project
例如,如果使用Hibernate 5.2或更高版本,则需要在Maven pom.xml配置文件中添加以下依赖项:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version> 
</dependency>

现在,您需要使用@MappedSuperclass在实体属性级别声明新类型,或者在基类的类级别声明新类型(更好):

@TypeDef(name = "json", typeClass = JsonType.class)

实体Map将如下所示:

@Type(type = "json")
@Column(columnDefinition = "json")
private Location location;

如果您使用的是Hibernate 5.2或更高版本,则MySQL57Dialect会自动注册JSON类型。
否则,您需要自己注册:

public class MySQLJsonDialect extends MySQL55Dialect {

    public MySQLJsonDialect() {
        super();
        this.registerColumnType(Types.JAVA_OBJECT, "json");
    }
}

并且,设置hibernate.dialect Hibernate属性以使用刚刚创建的MySQLJsonDialect类的全限定类名。

m0rkklqb

m0rkklqb3#

如果在响应客户端时(如rest API响应)需要将json type属性Map为json格式,则添加@JsonRawValue,如下所示:

@Column(name = "params", columnDefinition = "json")
@JsonRawValue
private String params;

这可能不会为服务器端使用进行DTOMap,但客户机将获得正确格式化为json的属性。

hkmswyz6

hkmswyz64#

很简单

@Column(name = "json_input", columnDefinition = "json")
private String field;

而在mysql数据库中您的列'json_input' json类型

u7up0aaq

u7up0aaq5#

对于那些不想写太多代码的人,有一个变通方案。
前端-〉在POST方法中将JSON对象编码为字符串base64,在GET方法中将其解码为json

In POST Method
data.components = btoa(JSON.stringify(data.components));

In GET
data.components = JSON.parse(atob(data.components))

后端-〉在您的JPA代码中,将列更改为String或BLOB,不需要Convert。

@Column(name = "components", columnDefinition = "json")
private String components;
41zrol4v

41zrol4v6#

在这个较新版本的 Spring Boot 和MySQL下面的代码是足够的

@Column( columnDefinition = "json" )
private String string;

我正面临着报价问题,所以我在我的项目线下行评论

#spring.jpa.properties.hibernate.globally_quoted_identifiers=true
3gtaxfhh

3gtaxfhh7#

我遇到过类似的问题,通过使用@Externalizer注解和Jackson来序列化/反序列化数据(@Externalizer是特定于OpenJPA的注解,因此您必须检查您的JPA实现是否存在类似的可能性),解决了这个问题。

@Persistent
@Column(name = "params")
@Externalizer("toJSON")
private Params params;

Params类实现:

public class Params {
    private static final ObjectMapper mapper = new ObjectMapper();

    private Map<String, Object> map;

    public Params () {
        this.map = new HashMap<String, Object>();
    }

    public Params (Params another) {
        this.map = new HashMap<String, Object>();
        this.map.putAll(anotherHolder.map);
    }

    public Params(String string) {
        try {
            TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
            };
            if (string == null) {
                this.map = new HashMap<String, Object>();
            } else {
                this.map = mapper.readValue(string, typeRef);
            }
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    public String toJSON() throws PersistenceException {
        try {
            return mapper.writeValueAsString(this.map);
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    public boolean containsKey(String key) {
        return this.map.containsKey(key);
    }

    // Hash map methods
    public Object get(String key) {
        return this.map.get(key);
    }

    public Object put(String key, Object value) {
        return this.map.put(key, value);
    }

    public void remove(String key) {
        this.map.remove(key);
    }

    public Object size() {
        return map.size();
    }
}

高温加热

wd2eg0qa

wd2eg0qa8#

如果您使用的是JPA版本2.1或更高版本,则可以使用这种情况。链接Persist Json Object
公共类HashMapConverter实现属性转换器〈Map〈字符串,对象〉,字符串〉{

@Override
public String convertToDatabaseColumn(Map<String, Object> customerInfo) {

    String customerInfoJson = null;
    try {
        customerInfoJson = objectMapper.writeValueAsString(customerInfo);
    } catch (final JsonProcessingException e) {
        logger.error("JSON writing error", e);
    }

    return customerInfoJson;
}

@Override
public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {

    Map<String, Object> customerInfo = null;
    try {
        customerInfo = objectMapper.readValue(customerInfoJSON, 
            new TypeReference<HashMap<String, Object>>() {});
    } catch (final IOException e) {
        logger.error("JSON reading error", e);
    }

    return customerInfo;
}

}

标准JSON对象将这些属性表示为HashMap:

@Convert(converter =哈希Map转换器. class)私有Map〈字符串,对象〉实体属性;

相关问题