Как разрешить столбец JSON в H2

Я использую в приложении MySQL 5.7, и у меня есть столбцы JSON. Когда я пытаюсь запустить тесты интеграции, это не работает, потому что база данных H2 не может создать таблицу. Это ошибка:

2016-09-21 16:35:29.729 ERROR 10981 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000389: Unsuccessful: create table payment_transaction (id bigint generated by default as identity, creation_date timestamp not null, payload json, period integer, public_id varchar(255) not null, state varchar(255) not null, subscription_id_zuora varchar(255), type varchar(255) not null, user_id bigint not null, primary key (id))
2016-09-21 16:35:29.730 ERROR 10981 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : Unknown data type: "JSON"; SQL statement:

Это класс сущности.

@Table(name = "payment_transaction")
public class PaymentTransaction extends DomainObject implements Serializable {

    @Convert(converter = JpaPayloadConverter.class)
    @Column(name = "payload", insertable = true, updatable = true, nullable = true, columnDefinition = "json")
    private Payload payload;

    public Payload getPayload() {
        return payload;
    }

    public void setPayload(Payload payload) {
        this.payload = payload;
    }
}

И подкласс:

public class Payload implements Serializable {

    private Long userId;
    private SubscriptionType type;
    private String paymentId;
    private List<String> ratePlanId;
    private Integer period;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public SubscriptionType getType() {
        return type;
    }

    public void setType(SubscriptionType type) {
        this.type = type;
    }

    public String getPaymentId() {
        return paymentId;
    }

    public void setPaymentId(String paymentId) {
        this.paymentId = paymentId;
    }

    public List<String> getRatePlanId() {
        return ratePlanId;
    }

    public void setRatePlanId(List<String> ratePlanId) {
        this.ratePlanId = ratePlanId;
    }

    public Integer getPeriod() {
        return period;
    }

    public void setPeriod(Integer period) {
        this.period = period;
    }

}

И этот конвертер для вставки в базу данных:

public class JpaPayloadConverter implements AttributeConverter<Payload, String> {

    // ObjectMapper is thread safe
    private final static ObjectMapper objectMapper = new ObjectMapper();

    private Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public String convertToDatabaseColumn(Payload attribute) {
        String jsonString = "";
        try {
            log.debug("Start convertToDatabaseColumn");

            // convert list of POJO to json
            jsonString = objectMapper.writeValueAsString(attribute);
            log.debug("convertToDatabaseColumn" + jsonString);

        } catch (JsonProcessingException ex) {
            log.error(ex.getMessage());
        }
        return jsonString;
    }

    @Override
    public Payload convertToEntityAttribute(String dbData) {

        Payload payload = new Payload();
        try {
            log.debug("Start convertToEntityAttribute");

            // convert json to list of POJO
            payload = objectMapper.readValue(dbData, Payload.class);
            log.debug("JsonDocumentsConverter.convertToDatabaseColumn" + payload);

        } catch (IOException ex) {
            log.error(ex.getMessage());
        }
        return payload;

    }
}

Ответ 1

H2 не имеет типа данных JSON.

JSON по существу является просто очень длинной строкой, поэтому вы можете использовать CLOB, который доступен для большинства баз данных.

Вам нужен тип JSON на уровне строк, только если вам нужна функция SQL, работающая на них, и только тогда, когда база данных настаивает на том, что ее функции JSON работают на JSON-типе, а не на CLOB.

Ответ 2

Я только что столкнулся с этой проблемой при работе с типом столбца JSONB - двоичной версией типа JSON, которая не отображается на TEXT.

Для дальнейшего использования вы можете определить пользовательский тип в H2, используя CREATE DOMAIN, следующим образом:

CREATE domain IF NOT EXISTS jsonb AS other;

Мне показалось, что это сработало и позволило мне успешно протестировать свой код на объекте.

Источник: https://objectpartners.com/2015/05/26/grails-postgresql-9-4-and-jsonb/

Ответ 3

Я решил проблему, используя тип TEXT в H2. Нужно создать отдельную базу данных script, чтобы создать схему в H2 для тестов и заменить тип JSON на TEXT.

Это по-прежнему проблема, поскольку, если вы используете Json-функцию в запросах, вы не сможете протестировать их с помощью H2.

Ответ 4

H2 не имеет тип данных JSON.

В MySQL тип JSON является просто псевдонимом для типа данных LONGTEXT, поэтому фактический тип данных для столбца будет LONGTEXT.

Ответ 5

В моем случае мы имели дело с типом PostgreSQL jsonb в производстве и H2 для наших тестов.

Я не смог протестировать решение @n00dle, потому что, по-видимому, Spring не поддерживает выполнение скрипта SQL до Hibernate ddl-auto=update для наших тестов, поэтому я использовал другой способ решения этой проблемы.

Вот суть для этого.

Общая идея заключается в создании двух файлов package-info. Один для производства, а другой для испытаний и регистрации различных типов (JsonBinaryType.class для производства и TextType.class для испытаний), чтобы обрабатывать их по-разному для PostgreSQL и H2