source

오류: 열이 json 유형이지만 최대 절전 모드에서 식이 다양한 유형의 문자입니다.

goodcode 2023. 8. 24. 23:06
반응형

오류: 열이 json 유형이지만 최대 절전 모드에서 식이 다양한 유형의 문자입니다.

스프링 데이터 jpa를 사용하여 엔티티 클래스 열 두 개를 postgres에 json으로 매핑해야 합니다.여러 스택 오버플로 게시물 및 배들둥 게시물을 읽은 후,

JPA로 지도 JSON 열을 Java Object에 매핑하는 방법

https://www.baeldung.com/hibernate-persist-json-object

아래와 같이 구성하였습니다.그러나 오류가 발생했습니다. "ERROR:"headers"는 json 유형이지만 식은 문자 유형이 다릅니다."

이 문제를 해결할 포인터를 제공하십시오.

아래와 같은 엔티티 클래스가 있습니다.

@Entity
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class Task {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;
    
    private String url;
    private String httpMethod;

    @Convert(converter = HashMapConverter.class)
    @Column(columnDefinition = "json")
    private Map<String, String> headers;

    @Convert(converter = HashMapConverter.class)
    @Column(columnDefinition = "json")
    private Map<String, String> urlVariables;
}

엔티티가 지속되는지 여부를 테스트하기 위해 테스트 클래스를 만들었습니다.이 Junit을 실행할 때 아래 테스트 사례가 아래와 같은 오류로 실패하고 있습니다.

enter image description here

@SpringBootTest
class TaskRepositoryTest {

    private static Task randomTask = randomTask();

    @Autowired
    private TaskRepository taskRepository;

    @BeforeEach
    void setUp() {
        taskRepository.deleteAll();
        taskRepository.save(randomTask);
    }

    public static Task randomTask() {
        return randomTaskBuilder().build();
    }

    public static TaskBuilder randomTaskBuilder() {
        Map<String,String> headers = new HashMap<>();
        headers.put(randomAlphanumericString(10),randomAlphanumericString(10));

        Map<String,String> urlVariables = new HashMap<>();
        urlVariables.put(randomAlphanumericString(10),randomAlphanumericString(10));

        return builder()
                .id(randomPositiveInteger())
                .httpMethod(randomAlphanumericString(10))
                .headers(headers)
                .urlVariables(urlVariables)
                .url(randomAlphanumericString(10)));
    }
}

liquibase를 사용하여 postgres DB에 테이블을 생성했고 열 데이터 유형을 json으로 볼 수 있었습니다.

databaseChangeLog:
  - changeSet:
      id: 1
      author: abc
      changes:
        - createTable:
            tableName: task
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: url
                  type: varchar(250)
                  constraints:
                    nullable: false
                    unique: true
              - column:
                  name: http_method
                  type: varchar(50)
                  constraints:
                    nullable: false
              - column:
                  name: headers
                  type: json
              - column:
                  name: url_variables
                  type: json
      rollback:
        - dropTable:
            tableName: task

이곳에 도착한 사람은 누구나 사용할 수 있습니다.JdbcTemplate이 오류를 해결하는 방법은 매우 간단합니다.SQL 문에서 다음을 사용하여 JSON 인수를 캐스트합니다.::jsonb.

예.String INSERT_SQL = "INSERT INTO xxx (id, json_column) VALUES(?, ?)";된다String INSERT_SQL = "INSERT INTO xxx (id, json_column) VALUES(?, ?::jsonb)";

위의 구성이 작동하지 않았습니다.

따라서 사용 사례를 해결하기 위해 아래 링크를 따라갔습니다.

https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/

"Provider com.fasterxml.jackson.module.jaxb.Spring Boot 업그레이드 후 "Jaxb Annotation Module을 찾을 수 없음"

pom.xml에 종속성이 추가되었습니다.

        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-jaxb-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vladmihalcea</groupId>
            <artifactId>hibernate-types-52</artifactId>
            <version>2.9.11</version>
        </dependency>

HashMapConverter 구성을 제거하고 엔티티 클래스에서 아래와 같이 변경했습니다.

@Entity
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@TypeDefs({
        @TypeDef(name = "json", typeClass = JsonStringType.class),
        @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class Task {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Integer id;
    
    private String url;
    private String httpMethod;

    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Map<String, String> headers;

    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Map<String, String> urlVariables;
}

이러한 변경 후에는 태스크테스트 통과.

다음을 사용한 대체 솔루션org.hibernate.annotations.ColumnTransformer

샘플 엔티티

import org.hibernate.annotations.ColumnTransformer;

@Entity
@Table
public class SomeEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;

  @Column(name = "some_class", columnDefinition = "jsonb")
  @Convert(converter = SomeClassConvertor.class)
  @ColumnTransformer(write = "?::jsonb")
  private SomeClass someClass;
}

샘플 변환기

import java.io.IOException;
import javax.persistence.AttributeConverter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.airtel.africa.entity.SomeClass;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SomeClassConvertor implements AttributeConverter<SomeClass, String> {
  @Autowired
  ObjectMapper objectMapper;

  @Override
  public String convertToDatabaseColumn(SomeClass someClass) {
    String someClassJson = null;
    try {
      someClassJson = objectMapper.writeValueAsString(someClass);
    } catch (final JsonProcessingException e) {
      log.error("JSON writing error", e);
    }

    return someClassJson;
  }

  @Override
  public SomeClass convertToEntityAttribute(String someClassJSON) {
    SomeClass someClass = null;
    if (StringUtils.isBlank(someClassJSON)) {
      return someClass;
    }
    try {
      someClass = objectMapper.readValue(someClassJSON, someClass.class);
    } catch (final IOException e) {
      log.error("JSON reading error", e);
    }
    return someClass;
  }
}

MySQL 8.0.21에서 Postgres 13으로 프로젝트를 마이그레이션할 때 이 문제가 발생했습니다.내 프로젝트는 최대 절전 모드 유형 종속성 버전 2.7.1과 함께 Spring boot을 사용합니다.저의 경우 해결책은 간단했습니다.

enter image description here

제가 해야 할 일은 그것을 바꾸는 것이었고 그것은 작동했습니다.

최대 절전 모드 유형 설명서 페이지에서 참조됩니다.

(후대를 위하여)완전히 안전하지는 않지만(문자열에서/문자열로 자동 캐스트) 제어하는 중요하지 않은 또는 데이터/구조에 적합한 대안이 있습니다.

postgresql 연결 문자열에 ?stringtype=unspecified를 추가합니다.

예: (application.yml에서)

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/dbname?stringtype=unspecified

이것은 postgresql이 당신의 문자열을 json에 자동으로 캐스트하도록 할 것입니다.추가 가져오기나 @type 정의 또는 사용자 지정 sql-query가 필요하지 않습니다. 질문의 예는 다음과 같습니다.

@Convert(converter = HashMapConverter.class)
@Column(columnDefinition = "json")
private Map<String, String> headers;

PPS: 저는 jsonb나 다른 데이터베이스 공급업체와 함께 이것을 시도해 본 적이 없습니다.

언급URL : https://stackoverflow.com/questions/65478350/error-column-is-of-type-json-but-expression-is-of-type-character-varying-in-hib

반응형