我在应用程序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;
}
}
H2没有JSON数据类型。
JSON本质上只是一个可能很长的字符串,因此您可以使用大多数数据库都可用的CLOB。
仅当您需要对它们进行操作的SQL函数,并且仅在数据库坚持其JSON函数对JSON类型而不是CLOB进行操作时,才需要在行级别使用JSON类型。
我只是在使用JSONB
列类型时遇到了这个问题-JSON
类型的二进制版本,它不映射到TEXT
。
为将来参考,您可以使用CREATE DOMAIN
在H2中定义自定义类型,如下所示:
CREATE domain IF NOT EXISTS jsonb AS other;
这似乎对我有用,并允许我针对实体成功测试我的代码。
来源:https://objectpartners.com/2015/05/26/grails-postgresql-9-4-and-jsonb/
我已经在H2中使用TEXT类型解决了这个问题。必须创建一个单独的数据库脚本才能在H2中创建测试模式,并用TEXT替换JSON类型。
这仍然是一个问题,因为如果您在查询中使用Json函数,则无法在使用H2时对其进行测试。
H2没有JSON数据类型。
在MySQL中,JSON类型只是LONGTEXT数据类型的别名,因此该列的实际数据类型将是LONGTEXT。
在我的情况下,我们在生产中处理PostgreSQL
jsonb
类型,而在测试中处理H2
。
我无法测试@ n00dle的解决方案,因为显然spring不支持在我们的测试SQL
的Hibernate
之前执行ddl-auto=update
脚本,所以我使用了另一种方法来解决这个问题。
这里是gist。
总体思路是创建两个package-info
文件。一个用于生产,另一个用于测试,并注册不同的类型(JsonBinaryType.class
用于生产,TextType.class
用于测试)以对PostgreSQL
和H2
]进行不同处理