我在自定义AttributeConverter
下面的实体将数据库中的字段保存为二进制数据。
TaskEntity.java
@Entity
@Table(name = "task")
public class TaskEntity {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private UUID id;
@Column(name = "state_machine_context")
@Convert(converter = StateMachineContextConverter.class)
private StateMachineContext<State, Event> stateMachineContext;
}
StateMachineContextConverter.java
@Converter
public class StateMachineContextConverter
implements AttributeConverter<StateMachineContext, byte[]> {
private static final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
kryo.addDefaultSerializer(StateMachineContext.class, new StateMachineContextSerializer());
kryo.addDefaultSerializer(MessageHeaders.class, new MessageHeadersSerializer());
kryo.addDefaultSerializer(UUID.class, new UUIDSerializer());
return kryo;
});
private static final int BUFFER_SIZE = 4096;
private static final int MAX_BUFFERED_SIZE = 10240;
@Override
public byte[] convertToDatabaseColumn(final StateMachineContext attribute) {
return serialize(attribute);
}
@Override
public StateMachineContext convertToEntityAttribute(final byte[] dbData) {
return deserialize(dbData);
}
private byte[] serialize(final StateMachineContext context) {
if (context == null) {
return null;
}
try (Output output = new Output(BUFFER_SIZE, MAX_BUFFERED_SIZE)) {
final Kryo kryo = kryoThreadLocal.get();
kryo.writeObject(output, context);
return output.toBytes();
}
}
private StateMachineContext deserialize(final byte[] data) {
if (data == null || data.length == 0) {
return null;
}
final Kryo kryo = kryoThreadLocal.get();
try (Input input = new Input(data)) {
return kryo.readObject(input, StateMachineContext.class);
}
}
}
因此,在使用带有@Transactional
注释 UPDATE 的方法中的SpringData nativeQuery选择TaskEntity之后,将为所有检索到的实体触发查询。
经过调查我认为它是因为hibernate的脏检查而发生的,因为上下文字段是从byte []转换的,并且由于某些原因它被hibernate认为是脏的。
有趣的是,使@Transactional(readOnly=true)
无效,因为Postgres抛出异常“无法在readOnly事务中更新”但如果我删除@Transactional
注释完全一切正常select后不会触发fine和UPDATE查询。
解决此问题的最佳解决方案是什么?也许有可能禁用readOnly事务的脏检查?是否可以为一个字段重写hibernate脏检查? I found that it is possible to overwrite dirty checking completely但我不想这样做。
答案 0 :(得分:5)
当我使用转换器将我的JSON字段从DB转换为自定义类时,我遇到了同样的问题。
Hibernate的脏检查策略从持久上下文(从DB中获取对象后立即保存)和当前实体调用实体上的.equals
方法。
所以覆盖StateMachineContext
的.equals方法应该为你做。它实际上对我有用。