我正在尝试使用jpa将某些数据持久保存到jsonb
列中。转换器似乎可以正常工作,但在内部出现此错误:
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1460)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:352)
at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47)
at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:452)
... 69 more
Caused by: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3167)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3682)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
... 77 more
Caused by: org.postgresql.util.PSQLException: ERROR: column "answers" is of type jsonb but expression is of type bytea
Hint: You will need to rewrite or cast the expression.
Position: 81
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2422)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2167)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:132)
at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:125)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.gjc.spi.jdbc40.ProfiledConnectionWrapper40$1.invoke(ProfiledConnectionWrapper40.java:437)
at com.sun.proxy.$Proxy367.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
... 85 more
]]
的代码如下:
@Entity
@Table(name = "question")
@EntityListeners({ CreatedOnListener.class })
public class Question implements ICreatedOn {
@Id
@GeneratedValue
private long id;
@Column(name = "q_text", length = 600)
private String text;
@Column(name = "pic_url", length = 400)
private String picUrl;
@Enumerated(EnumType.STRING)
@Column(name = "q_type")
private QuestionType type;
@Convert(converter = AnswerJTypeConverter.class)
@Column(name = "answers", columnDefinition = "jsonb")
private List<AnswerJType> answers = new ArrayList<>();
public class AnswerJTypeConverter implements AttributeConverter<List<AnswerJType>, PGobject> {
private static ObjectMapper MAPPER = new ObjectMapper();
@Override
public PGobject convertToDatabaseColumn(List<AnswerJType> answers) {
if (answers == null)
return null;
ObjectNode answersJson = MAPPER.createObjectNode();
answers.forEach(a -> {
ObjectNode ansNode = MAPPER.createObjectNode();
ansNode.put("text", a.getText());
ansNode.put("picUrl", a.getPicUrl());
answersJson.set("" + a.getId(), ansNode);
});
PGobject jsonb = new PGobject();
jsonb.setType("jsonb");
try {
jsonb.setValue(answersJson.toString());
} catch (SQLException e) {
throw new RuntimeException(e);
}
return jsonb;
}
@Override
public List<AnswerJType> convertToEntityAttribute(PGobject dbData) {
try {
if (dbData.getType().equals("jsonb")) {
String colValue = dbData.getValue();
JsonNode answersJson = MAPPER.readTree(colValue);
Iterator<Entry<String, JsonNode>> fields = answersJson.fields();
List<AnswerJType> answers = new ArrayList<>();
while (fields.hasNext()) {
Entry<String, JsonNode> next = fields.next();
JsonNode answer = next.getValue();
AnswerJType ans = new AnswerJType();
ans.setId(Long.parseLong(next.getKey()));
if (answer.has("text")) {
ans.setText(answer.get("text").asText());
}
if (answer.has("picUrl")) {
ans.setPicUrl(answer.get("picUrl").asText());
}
answers.add(ans);
}
return answers;
}
throw new RuntimeException("PGobject type is not jsonb.");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
我只是不知道问题出在哪里,因为我的列在数据库中的类型为jsonb
,而我的columnDefinition
也是jsonb
。有什么想法吗?